Los emails de alerta de seguridad son fundamentales para proteger las cuentas de usuario. Deben ser claros, accionables y llegar al instante. Aquí te explico cómo diseñar notificaciones de seguridad efectivas.
Tipos de alertas de seguridad
Notificaciones de inicio de sesión
interface LoginAlert {
user: { email: string; name: string };
login: {
timestamp: Date;
ip: string;
location?: { city: string; country: string };
device: string;
browser: string;
};
isNewDevice: boolean;
isNewLocation: boolean;
}
await sendEmail({
to: user.email,
subject: login.isNewDevice
? 'New device signed in to your account'
: 'New sign-in to your account',
template: 'login-alert',
data: {
user,
login,
secureAccountUrl: `${baseUrl}/security`,
notYouUrl: `${baseUrl}/security/report?session=${sessionId}`
},
priority: 'high'
});
Confirmación de cambio de contraseña
await sendEmail({
to: user.email,
subject: 'Your password was changed',
template: 'password-changed',
data: {
user,
changedAt: new Date(),
device: request.device,
location: request.location,
resetUrl: `${baseUrl}/reset-password`,
supportEmail: '[email protected]'
}
});
Advertencia de actividad sospechosa
interface SuspiciousActivityAlert {
user: User;
activity: {
type: 'failed_logins' | 'unusual_location' | 'api_abuse' | 'data_export';
details: string;
timestamp: Date;
riskLevel: 'low' | 'medium' | 'high';
};
recommendedActions: string[];
}
await sendEmail({
to: user.email,
subject: '⚠️ Unusual activity detected on your account',
template: 'suspicious-activity',
data: {
user,
activity,
recommendedActions: [
'Change your password',
'Review recent activity',
'Enable two-factor authentication'
],
securityDashboardUrl: `${baseUrl}/security`,
lockAccountUrl: `${baseUrl}/security/lock?token=${lockToken}`
},
priority: 'high'
});
Emails de autenticación de dos factores
Confirmación de 2FA activada
await sendEmail({
to: user.email,
subject: 'Two-factor authentication enabled',
template: '2fa-enabled',
data: {
user,
method: '2fa.method', // 'authenticator' | 'sms' | 'email'
backupCodes: user.hasBackupCodes,
manageUrl: `${baseUrl}/security/2fa`
}
});
Códigos de respaldo regenerados
await sendEmail({
to: user.email,
subject: 'New backup codes generated',
template: 'backup-codes-regenerated',
data: {
user,
generatedAt: new Date(),
device: request.device,
warning: 'Your old backup codes no longer work',
viewCodesUrl: `${baseUrl}/security/backup-codes`
}
});
Gestión de sesiones y dispositivos
Nuevo dispositivo agregado
await sendEmail({
to: user.email,
subject: 'New device added to your account',
template: 'new-device',
data: {
user,
device: {
name: deviceInfo.name,
type: deviceInfo.type,
browser: deviceInfo.browser,
os: deviceInfo.os,
addedAt: new Date()
},
location: deviceInfo.location,
removeDeviceUrl: `${baseUrl}/security/devices/${deviceId}/remove`,
viewAllDevicesUrl: `${baseUrl}/security/devices`
}
});
Todas las sesiones cerradas
await sendEmail({
to: user.email,
subject: 'All sessions signed out',
template: 'sessions-terminated',
data: {
user,
terminatedAt: new Date(),
terminatedBy: 'you', // or 'admin' or 'security_system'
sessionsCount: terminatedCount,
reason: 'Password change', // or 'Security concern' or 'User request'
signInUrl: `${baseUrl}/login`
}
});
Alertas de API y tokens de acceso
Clave de API creada
await sendEmail({
to: user.email,
subject: 'New API key created',
template: 'api-key-created',
data: {
user,
apiKey: {
name: key.name,
prefix: key.prefix, // First 8 chars only
permissions: key.permissions,
createdAt: new Date()
},
manageKeysUrl: `${baseUrl}/settings/api-keys`
}
});
Actividad inusual de la API
await sendEmail({
to: user.email,
subject: 'Unusual API activity detected',
template: 'api-activity-alert',
data: {
user,
activity: {
keyName: key.name,
requestCount: activity.count,
timeWindow: '1 hour',
normalRange: '100-500 requests',
actualCount: activity.count
},
revokeKeyUrl: `${baseUrl}/settings/api-keys/${key.id}/revoke`,
viewLogsUrl: `${baseUrl}/settings/api-keys/${key.id}/logs`
}
});
Flujo de cambio de email
Cambio de email solicitado
// Send to OLD email
await sendEmail({
to: user.currentEmail,
subject: 'Email change requested',
template: 'email-change-requested',
data: {
user,
newEmail: maskEmail(newEmail),
requestedAt: new Date(),
cancelUrl: `${baseUrl}/security/email-change/cancel?token=${cancelToken}`,
expiresIn: '24 hours'
}
});
// Send to NEW email
await sendEmail({
to: newEmail,
subject: 'Verify your new email address',
template: 'email-change-verify',
data: {
user,
verifyUrl: `${baseUrl}/security/email-change/verify?token=${verifyToken}`,
expiresIn: '24 hours'
}
});
Buenas prácticas de alertas de seguridad
Prioridad y tiempos
const securityEmailConfig = {
// Immediate, high priority
immediate: [
'password_changed',
'email_changed',
'suspicious_activity',
'2fa_disabled',
'all_sessions_terminated'
],
// Can batch or slight delay
batchable: [
'new_login_known_device',
'api_key_created',
'settings_changed'
]
};
async function sendSecurityAlert(type: string, data: any) {
const isImmediate = securityEmailConfig.immediate.includes(type);
await sendEmail({
...data,
priority: isImmediate ? 'high' : 'normal',
headers: {
'X-Priority': isImmediate ? '1' : '3',
'X-Security-Alert': 'true'
}
});
}
Acciones claras
// Always include:
// 1. What happened
// 2. When it happened
// 3. What to do if it was you
// 4. What to do if it wasn't you
const securityEmailStructure = {
whatHappened: 'Your password was changed',
when: formatDateTime(event.timestamp),
where: `${event.location.city}, ${event.location.country}`,
device: event.device,
ifYou: 'No action needed. You can ignore this email.',
ifNotYou: {
actions: [
{ label: 'Reset your password', url: resetUrl },
{ label: 'Contact support', url: supportUrl }
],
urgency: 'Do this immediately to secure your account'
}
};
Mejores prácticas
- —Enviar de inmediato - Las alertas de seguridad deben llegar en tiempo real
- —Asuntos claros - El usuario debe entender el problema solo con leer el asunto
- —Incluir contexto - Hora, ubicación e información del dispositivo
- —Proporcionar acciones - Pasos claros para ambos escenarios
- —No incluir datos sensibles - Nada de contraseñas ni tokens completos en los emails
- —Branding consistente - Para que los usuarios reconozcan alertas legítimas
- —Probar la entregabilidad - Los emails de seguridad deben llegar a la bandeja de entrada, no a spam
Las alertas de seguridad generan confianza. Cuando los usuarios saben que estás velando por su seguridad, se sienten más seguros usando tu producto.