<!-- AGENTE: MAILS PABLO | FECHA: 260217 -->

# Agente Mails Pablo

Agente para gestion de correo electronico en el servidor Pablo (`ssh pablo`).

**Tareas activas:** Consultar `00_IA/tareas/mail.md` al inicio de sesión para ver hilos abiertos y próximos pasos.

---

## PROTOCOLO DE ENVÍO (OBLIGATORIO)

**NUNCA enviar un email directamente.** Tres pasos:

1. **Recopilar** — Destinatario, remitente (alias), asunto, datos relevantes
2. **Redactar** — Mostrar borrador completo al usuario: De, Para, Asunto y Cuerpo
3. **Confirmar** — Esperar aprobación explícita antes de enviar

---

## Infraestructura de Correo

### Servicios

| Servicio | Puerto | Contenedor/Proceso | Función |
|----------|--------|--------------------|---------|
| Haraka | 25, 587 | systemd (haraka.service) | SMTP: recepción y envío autenticado |
| Dovecot | 24 (LMTP), 143 (IMAP) | systemd (dovecot.service) | IMAP + entrega local LMTP |
| SnappyMail | 8280 | snappymail | Webmail (mail.tzzr.me) |
| Mail UI | 3080 | systemd (mail-ui.service) | Interfaz gestión (/opt/mail-ui) |

### Dominios

tzzr.pro, tzzr.me, tzr.systems, tzr.es

### Cuentas (buzones reales)

| Email | Descripción | Maildir |
|-------|-------------|---------|
| tzzrinbox@tzzr.pro | Bandeja Personal | /var/mail/vhosts/tzzr.pro/tzzrinbox/ |
| tzzrinbox@tzr.systems | Bandeja Empresa Servidores | /var/mail/vhosts/tzr.systems/tzzrinbox/ |
| tzzrinbox@tzzr.me | Bandeja Servicios Servidor | /var/mail/vhosts/tzzr.me/tzzrinbox/ |

Los aliases (info@, admin@, paypal@, etc.) redirigen a estas cuentas. Configurados en `tzzr_communications.mail_aliases`.

### Credenciales

Consultar siempre PostgreSQL:
```bash
ssh pablo "docker exec tzzr-postgres psql -U tzzr -d tzzr -c \"SELECT email, secret FROM tzzr_communications.mail_accounts WHERE activo = true;\""
```

---

## Operaciones

### Leer emails

```bash
# Buscar emails por remitente/asunto
ssh pablo "grep -rli 'TERMINO' /var/mail/vhosts/ 2>/dev/null | grep -v 'cache\|index\|dovecot'"

# Leer email concreto (descargar y parsear)
ssh pablo "cat 'RUTA_ARCHIVO'" > /tmp/email.eml
python3 -c "
import email, re, html

with open('/tmp/email.eml', 'rb') as f:
    msg = email.message_from_bytes(f.read())

print('De:', msg['From'])
print('Para:', msg['To'])
print('Fecha:', msg['Date'])

# Decodificar subject
subj = email.header.decode_header(msg['Subject'])
subj_str = ''.join(
    p.decode(e or 'utf-8', errors='replace') if isinstance(p, bytes) else p
    for p, e in subj
)
print('Asunto:', subj_str)

# Extraer body
for part in msg.walk():
    ct = part.get_content_type()
    charset = part.get_content_charset() or 'utf-8'
    if ct == 'text/plain':
        print(part.get_payload(decode=True).decode(charset, errors='replace'))
        break
"

# Consultar emails desde BD
ssh pablo "docker exec tzzr-postgres psql -U tzzr -d tzzr -c \"SELECT from_address, subject, created_at, direction FROM tzzr_communications.mail ORDER BY created_at DESC LIMIT 20;\""
```

### Carpetas Maildir (tzzr.pro)

| Carpeta | Ruta relativa |
|---------|---------------|
| Inbox | cur/ |
| Enviados | .Enviados/cur/ |
| Papelera | .Papelera/cur/ |
| Notificaciones | .Notificaciones/ |
| Medios de Pago | .Medios de Pago/ |
| Online | .Online/ |
| Pablo | .Pablo/ |
| Compras | .Compras/ |

### Enviar email

Los emails outbound se envían via SMTP local (Haraka) y se guardan automáticamente en:
- BD PostgreSQL (`tzzr_communications.mail`, direction='outbound')
- Carpeta Enviados del maildir (pendiente de verificar stream save)

```python
# Envío via SMTP local con guardado automático
import smtplib
from email.mime.text import MIMEText
from email.utils import formatdate, make_msgid

msg = MIMEText(body, 'plain', 'utf-8')
msg['From'] = 'NOMBRE <alias@dominio>'
msg['To'] = 'DEST <dest@dominio>'
msg['Subject'] = 'Asunto'
msg['Date'] = formatdate(localtime=True)
msg['Message-ID'] = make_msgid(domain='mail.tzzr.me')
# Para respuestas en hilo:
msg['In-Reply-To'] = '<message-id-original>'
msg['References'] = '<refs anteriores> <message-id-original>'

smtp = smtplib.SMTP('localhost', 25)
smtp.sendmail('alias@dominio', ['dest@dominio'], msg.as_string())
smtp.quit()
```

**Nota:** Al enviar por smtplib directo, Haraka guarda en la BD automáticamente. Para asegurar copia en Enviados maildir, guardar manualmente:

```python
import os, time, crypto

sent_dir = '/var/mail/vhosts/DOMINIO/tzzrinbox/.Enviados/cur'
ts = int(time.time())
fname = f'{ts}.M000000P000000.deck-pablo,S={len(msg.as_bytes())}:2,S'
fpath = os.path.join(sent_dir, fname)

with open(fpath, 'wb') as f:
    f.write(msg.as_bytes())

os.chown(fpath, 116, 120)  # dovecot:dovecot
```

---

## Base de Datos

### Tabla principal: tzzr_communications.mail

Campos clave:
- `mrf` — ID único (PK)
- `from_address`, `to_address`, `subject`, `body`
- `direction` — 'inbound' | 'outbound'
- `message_id`, `in_reply_to` — Para hilos
- `folder` — 'inbox' | 'sent'
- `read`, `starred` — Estados
- `account` — Cuenta asociada
- `headers` — JSONB con cabeceras

### Tablas auxiliares

- `tzzr_communications.mail_accounts` — Cuentas SMTP (email, secret, activo)
- `tzzr_communications.mail_aliases` — Aliases (alias → destino)

---

## Plugins Haraka (/opt/haraka/plugins/)

| Plugin | Función |
|--------|---------|
| auth_postgresql.js | Autenticación SMTP contra mail_accounts |
| rcpt_to_postgresql.js | Verificación de destinatarios y resolución de aliases |
| queue_lmtp.js | Entrega local (LMTP) + outbound (relay) + guardado en BD |
| queue_postgresql.js | Guardado en BD (no activo, integrado en queue_lmtp) |

Config Haraka: `/opt/haraka/config/`
Dominios locales: `/opt/haraka/config/host_list`

---

## Troubleshooting

```bash
# Estado de servicios
ssh pablo "systemctl status haraka dovecot mail-ui"

# Logs Haraka
ssh pablo "journalctl -u haraka --since '1 hour ago' --no-pager"

# Logs Dovecot
ssh pablo "journalctl -u dovecot --since '1 hour ago' --no-pager"

# Verificar entrega LMTP
ssh pablo "echo '' | nc -q1 127.0.0.1 24"

# Reindexar Dovecot
ssh pablo "doveadm force-resync -u tzzrinbox@tzzr.pro '*'"
```