Configuración de email¶
Cómo configurar el envío de emails transaccionales (invitaciones, recordatorios de evaluación, reset de contraseña, etc.).
Modelo de dos niveles¶
TenantEmailSettings (configuración del tenant)
│
│ Si está deshabilitado o falla
▼
PlatformEmailSettings (fallback global del SystemAdmin)
│
│ Si tampoco está habilitado
▼
Email NO se envía (queda en log)
Cada tenant decide: - Usar el SMTP global del SystemAdmin (sin setup técnico de su lado, más rápido) - Configurar su propio proveedor (más control, dirección remitente propia, mejor entregabilidad)
Proveedores soportados¶
Cuatro opciones (EmailProvider enum):
| Proveedor | Cuándo conviene |
|---|---|
UseFallback |
Default. Usa el SMTP global de plataforma sin configurar nada |
Smtp |
SMTP corporativo (Office 365 con SMTP Auth, SendGrid SMTP, Mailgun SMTP, servidor propio) |
MicrosoftOAuth |
Microsoft 365 con OAuth (sin password — cliente Azure AD con Mail.Send) |
GoogleOAuth |
Google Workspace con OAuth (refresh token) |
Configuración a nivel tenant¶
Email del tenant (menú lateral, rol TenantAdmin).
A) UseFallback (default)¶
Sin configuración. Tu tenant usa el SMTP global. La dirección remitente es la que configuró el SystemAdmin (ej. noreply@eval360pro.com).
Pros: cero setup. Contras: no se ve "tuyo".
B) SMTP¶
Campos:
| Campo | Detalle |
|---|---|
| Host | ej. smtp.office365.com, smtp.sendgrid.net, smtp.gmail.com |
| Puerto | 587 (STARTTLS) o 465 (SSL/TLS) |
| SSL/TLS | Habilitar para 465; STARTTLS automático en 587 |
| Username | Usuario SMTP |
| Password | Contraseña o app-password |
| From address | Email remitente (puede requerir verificación en proveedor) |
| From display name | Nombre visible (ej. "Equipo de RR.HH. Acme") |
Click Enviar prueba → ingresar email destinatario → si llega, está OK.
La contraseña se guarda encriptada (AES-256) en DB. Solo se descifra en runtime.
C) Microsoft Graph (OAuth)¶
Pre-requisito: tener una app registration en Azure AD con permiso Mail.Send de tipo Application (no delegated), con admin consent.
Campos:
| Campo | Detalle |
|---|---|
| Tenant ID (Azure) | GUID del tenant Azure AD |
| Client ID | App ID de la app registration |
| Client Secret | Secret generado en la app registration |
| User ID | UPN o GUID del buzón emisor (ej. noreply@acme.com) |
| From display name | Nombre visible |
Botón Enviar prueba valida el flujo OAuth + envío.
El client secret se guarda encriptado.
D) Gmail OAuth¶
Pre-requisito: tener una OAuth app en Google Cloud Console con scope https://www.googleapis.com/auth/gmail.send, y haber obtenido un refresh token vía OAuth dance (suele ser un script one-shot que el admin corre).
Campos:
| Campo | Detalle |
|---|---|
| Client ID | OAuth client ID de Google Cloud |
| Client Secret | OAuth client secret |
| Refresh Token | Token de refresh obtenido en el OAuth dance inicial |
| From address | Email remitente (debe ser el del usuario que autorizó) |
| From display name | Nombre visible |
Botón Enviar prueba.
Client secret y refresh token se guardan encriptados.
Configuración a nivel plataforma (SystemAdmin)¶
Email plataforma (fallback) — solo SystemAdmin.
Mismo formulario que un tenant tendría, pero el scope es global: - Habilitado / deshabilitado - From address, display name - Host, puerto, SSL - Usuario, contraseña
Si está deshabilitado y un tenant no tiene SMTP propio, los emails fallan (queda en log de Serilog como EMAIL_FAIL).
Recomendación: configurar el fallback de plataforma con un SMTP confiable (SendGrid, Mailgun) para que los tenants nuevos (que aún no configuraron nada) sigan recibiendo emails.
Plantillas de email¶
Las plantillas (qué dice cada email) se gestionan aparte:
- TenantAdmin / HRManager → Plantillas de email → personalizar para su tenant
- SystemAdmin → Plantillas email (plataforma) → editar el default global
Ver Quickstart TenantAdmin — sección 5 para el editor en detalle.
Eventos donde se dispara email¶
| Evento | Plantilla | Destinatarios |
|---|---|---|
| Crear empleado con cuenta | invitation |
El nuevo empleado |
| Abrir un ciclo de evaluación | cycle-opened |
Todos los evaluadores con al menos una evaluación pendiente |
| Recordatorio manual antes del deadline | deadline-reminder |
Evaluadores con evaluaciones aún no enviadas |
| Cerrar ciclo / publicar resultados | results-published |
Los subjects (los evaluados) |
| Crear/aprobar plan de desarrollo | plan-assigned |
El empleado del plan |
| Solicitar reset de contraseña | password-reset |
El usuario que lo solicitó |
Encriptación de secretos¶
Todas las contraseñas, secrets y refresh tokens (de SMTP, Microsoft Graph, Gmail) se almacenan cifrados con AES-256-CBC.
La clave maestra (Email.MasterKey) se carga desde appsettings.Production.json o variables de entorno. No se commitea en el repo. Si esa clave cambia, los secretos guardados antes dejan de poder descifrarse y hay que re-ingresarlos.
Generar una key nueva (32 bytes en base64):
[Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))
Troubleshooting¶
| Problema | Causa típica |
|---|---|
| Test de SMTP devuelve "Authentication failed" | Usuario o contraseña mal · cuenta requiere app-password (Office 365 con MFA) · SMTP Auth deshabilitado en el tenant |
| Test de Microsoft Graph devuelve 403 | Permiso Mail.Send no tiene admin consent · User ID no existe o no tiene mailbox |
| Test de Gmail devuelve "invalid_grant" | Refresh token expirado o revocado por Google · re-hacer OAuth dance |
| Emails no llegan pero el test dice OK | Spam folder · email remitente sin SPF/DKIM/DMARC · IP del SMTP en blacklist |
| Error "Email:MasterKey debe ser de 32 bytes" | La clave maestra en appsettings tiene el largo equivocado al decodificar base64. Generar de nuevo |