Sistema de Correo

NoxPanel gestiona un sistema de correo completo con autodiscovery, DKIM, certificados TLS por dominio y compatibilidad con todos los clientes de correo (Outlook, Thunderbird, Apple Mail, móviles).

Visión General

Cuando se crea un sitio con provision_full_site(), el sistema configura automáticamente todo lo necesario para que el correo funcione:

  1. Registros DNS para mail, imap, smtp, pop, autodiscover, autoconfig

  2. Rutas Traefik + certificados Let’s Encrypt para todos los subdominios

  3. Sincronización SNI de certificados a Dovecot y Postfix

  4. Firmas DKIM para autenticación de correo saliente

  5. Autodiscovery compatible con Outlook, Thunderbird y clientes móviles

Pipeline Completo

Paso 1: Registros DNS (automático)

provision_full_site()_provision_bind_zone() crea los siguientes registros:

Nombre

Tipo

Valor

Propósito

mail.dominio.com

A

IP del servidor

Servidor de correo principal

imap.dominio.com

A

IP del servidor

Acceso IMAP

smtp.dominio.com

A

IP del servidor

Envío SMTP

pop.dominio.com

A

IP del servidor

Acceso POP3

autodiscover.dominio.com

A

IP del servidor

Outlook autodiscovery

autoconfig.dominio.com

A

IP del servidor

Thunderbird autoconfig

dominio.com

MX

mail.dominio.com (pri 10)

Recepción de correo

dominio.com

TXT (SPF)

v=spf1 a mx ip4:{IP} ~all

Autenticación SPF

_dmarc.dominio.com

TXT

v=DMARC1; p=none; ...

Política DMARC

_imaps._tcp

SRV

0 1 993 imap.dominio.com

IMAP sobre TLS

_submission._tcp

SRV

0 1 587 smtp.dominio.com

SMTP STARTTLS

_submissions._tcp

SRV

0 1 465 smtp.dominio.com

SMTP sobre TLS

_autodiscover._tcp

SRV

0 1 443 autodiscover.dominio.com

Outlook SRV autodiscovery

Important

autodiscover y autoconfig deben ser registros A (no CNAMEs). Los SRV records requieren que el target sea un registro A, y Outlook verifica el hostname directamente.

Paso 2: Rutas Traefik + Certificados LE (automático)

Ubicación: hosting/traefik.py

El router de mail incluye Host rules para todos los subdominios:

rule = "Host(`mail.{domain}`) || Host(`imap.{domain}`) || " \
       "Host(`smtp.{domain}`) || Host(`pop.{domain}`) || " \
       "Host(`autodiscover.{domain}`) || Host(`autoconfig.{domain}`) || " \
       "Host(`webmail.{domain}`)"

Con certResolver: letsencrypt, Traefik emite automáticamente un certificado SAN que cubre todos los subdominios de correo. El certificado se almacena en /opt/data/traefik/letsencrypt/acme.json.

Paso 3: Sincronización SNI (cron cada 15 min)

Script: app/scripts/sync_sni_certs.sh

Los servicios de correo (Dovecot, Postfix) necesitan certificados TLS que coincidan con el hostname SNI del cliente. Este script extrae los certificados de acme.json y los despliega.

Proceso:

  1. Lee acme.json y extrae certificados para cada dominio

  2. Para cada dominio con correo configurado:

    1. Extrae cert+key para mail.{d}, imap.{d}, smtp.{d}, pop.{d}

    2. Escribe ficheros PEM en hosting-core

    3. Actualiza 10-ssl.conf de Dovecot (bloques local_name)

    4. Actualiza sni_maps de Postfix

  3. Reinicia servicios

Cron (en el host):

*/15 * * * * /opt/data/NoxPanel/app/scripts/sync_sni_certs.sh \
    >> /var/log/sync_sni_certs.log 2>&1

Warning

Postfix requiere stop && start completo (NO reload/HUP). Los procesos smtpd cachean los mapas SNI en memoria y no los recargan con un simple reload.

Paso 4: DKIM (automático via provision_full_site)

Ubicación: hosting/services.py_setup_dkim_for_domain()

Genera claves DKIM de 2048 bits y configura OpenDKIM:

  1. Genera par de claves RSA 2048-bit

  2. Escribe la clave privada en /etc/opendkim/keys/{domain}/default.private

  3. Configura las tablas de OpenDKIM:

    • /etc/opendkim/SigningTable: mapea *@{domain}default._domainkey.{domain}

    • /etc/opendkim/KeyTable: mapea el selector → fichero de clave

    • /etc/opendkim/TrustedHosts: añade el dominio

  4. Recarga OpenDKIM

  5. Crea el registro DNS TXT default._domainkey con la clave pública

Ejecución manual para todos los dominios:

docker exec noxpanel-web-1 python manage.py setup_dkim --all

Paso 5: Microsoft AutoDetect (automático)

El nuevo Outlook y aplicaciones móviles de Microsoft usan un servicio cloud (prod-autodetect.outlookmobile.com) que no consulta DNS directamente:

  1. Microsoft probes imap.{domain}:993 y smtp.{domain}:587 desde sus servidores

  2. Verifica que hay un certificado TLS válido que coincida con el SNI hostname

  3. Si todo es correcto, configura la cuenta como IMAP automáticamente

Puntos críticos:

  • autodiscover.json DEBE devolver 404: cualquier respuesta provoca que Microsoft clasifique la cuenta como Exchange (EAS), ignorando IMAP

  • autodiscover.xml sirve para Outlook desktop V1 (protocolo clásico)

  • Los certificados SNI deben estar correctos (paso 3) para que el probe funcione

Webmail (Roundcube)

Roundcube está integrado como servicio Docker, accesible en /webmail/.

  • Proxy via nginx: /webmail/roundcube:80

  • Logo whitelabel dinámico: /webmail/skins/elastic/images/whitelabel-logo → Django API

  • Sesiones y cookies correctamente prefijadas con /webmail/

Los subdominios webmail.{domain} redireccionan automáticamente a /webmail/.

Verificación de Correo

El sistema DNS Checker (hosting/dns_checker.py) verifica 18 elementos:

  • 14 registros DNS: NS, A (7), CNAME (2), MX, TXT (SPF, DMARC), SRV (4)

  • 4 conectividades: IMAP:993, SMTP:587, HTTP:80, HTTPS:443

Accesible desde el dashboard de hosting por cada dominio.

Troubleshooting

El correo no se recibe (MX incorrecto):

dig MX dominio.com +short
# Debe devolver: 10 mail.dominio.com.

Certificado TLS inválido para IMAP/SMTP:

# Verificar que sync_sni_certs.sh está corriendo
tail -20 /var/log/sync_sni_certs.log

# Verificar certificado en Dovecot
docker exec noxpanel-hosting-core-1 openssl s_client \
    -connect localhost:993 -servername imap.dominio.com < /dev/null 2>&1 | \
    head -20

DKIM no pasa verificación:

# Verificar registro DNS
dig TXT default._domainkey.dominio.com +short

# Verificar que OpenDKIM está firmando
docker exec noxpanel-hosting-core-1 cat /etc/opendkim/SigningTable | grep dominio

Outlook configura como Exchange en vez de IMAP:

Verificar que autodiscover.json devuelve 404:

curl -sI https://autodiscover.dominio.com/autodiscover/autodiscover.json
# Debe devolver: 404