aboutsummaryrefslogtreecommitdiffstats

posta

Read this in English

posta es un cliente de correo IMAP/SMTP chiquito y genérico para tu terminal. Un solo binario, salida JSON por defecto y cuentas con nombre en un archivo TOML — tu casilla queda tan scripteable como cualquier otra API.

El nombre viene de las postas: las estaciones de relevo del correo colonial sudamericano. Y en Argentina, la posta es también lo genuino, la verdad.

$ posta list --unread --max 3 --format table
   UID      DATE                    FROM                              SUBJECT
  7121  ●   Fri, 17 Jul 2026 17:0…  "Proveedor" <facturas@isp.ex…     Tu factura está lista
  7120  ●   Fri, 17 Jul 2026 15:0…  Meetup <eventos@meetup.exam…      🚀 Inscripción abierta
  7119  ●   Fri, 17 Jul 2026 10:1…  "banco@example.com"               Aviso de tarjeta

$ posta search 'FROM banco UNSEEN' | jq .uids
[7119, 7118, 7117]

Características

  • Funciona con cualquier proveedor — IMAP/SMTP con STARTTLS (imap://, smtp://) o TLS implícito (imaps://, smtps://). Tu propio servidor, Gmail, Fastmail, lo que sea.
  • Múltiples cuentas — cuentas con nombre en un solo archivo, cambiadas con --account, $POSTA_ACCOUNT o un default_account.
  • Amigable para scripts — todos los comandos imprimen JSON (canalizalo a jq), con --format table para humanos.
  • Secretos a tu manera — contraseñas literales (posta revisa los permisos del archivo y te avisa si están flojos) o password_cmd para sacarlas de pass, un keyring o cualquier comando.
  • Seguro por defecto — leer nunca marca mensajes como leídos (BODY.PEEK en todos lados); optás con --mark-read o posta mark read.
  • Sin archivo de config si no querés — todo puede venir de variables de entorno POSTA_*, útil para CI y scripts sueltos.

Instalación

git clone https://git.all.ar/pub/posta.git
cd posta
cargo install --path .

Configuración

~/.config/posta/config.toml (o $POSTA_CONFIG, o --config ARCHIVO):

default_account = "personal"

[accounts.personal]
email = "alice@example.com"
display_name = "Alice Example"
imap_url = "imap://alice@example.com@mail.example.com:143"
smtp_url = "smtp://alice@example.com@mail.example.com:587"
password_cmd = "pass show mail/personal"   # o: password = "..." (¡chmod 600!)

[accounts.trabajo]
email = "alice@work.example"
imap_url = "imaps://alice@imap.work.example"    # TLS implícito, puerto 993
smtp_url = "smtps://alice@smtp.work.example"    # TLS implícito, puerto 465
password_cmd = "secret-tool lookup mail trabajo"
sent_folder = "Sent Items"
trash_folder = "Deleted"

El usuario de la URL puede contener @ (imap://alice@example.com@mail.example.com); el host empieza después del último. imap_password[_cmd] / smtp_password[_cmd] pisan la contraseña compartida por protocolo cuando difieren.

Las variables de entorno pisan cualquier campo de la cuenta elegida: POSTA_IMAP_URL, POSTA_SMTP_URL, POSTA_PASSWORD, POSTA_PASSWORD_CMD, POSTA_IMAP_PASSWORD, POSTA_SMTP_PASSWORD, POSTA_EMAIL, POSTA_DISPLAY_NAME, POSTA_SENT_FOLDER, POSTA_TRASH_FOLDER, más POSTA_ACCOUNT y POSTA_CONFIG.

Uso

posta accounts                       # cuentas configuradas
posta status                         # totales y sin leer
posta folders                        # listar carpetas
posta list --unread                  # más recientes primero
posta list --query 'FROM banco SINCE 1-Jul-2026'
posta get 7119                       # headers + cuerpo de texto, en JSON
posta get 7119 --html                # preferir la parte HTML
posta get 7119 --raw > msg.eml       # fuente RFC 822 crudo
posta send --to bob@example.com --subject 'Hola' --body '¡Hola!'
git log | posta send --to bob@example.com --subject 'Changelog'
posta mark read 7119 7120            # también: unread, flagged, unflagged
posta move 7119 --to Archives
posta delete 7119                    # mueve a la papelera
posta search 'FROM banco UNSEEN'     # IMAP SEARCH crudo, imprime UIDs

Flags globales: --account/-a NOMBRE, --config ARCHIVO, --format json|table, y --folder en los comandos que operan sobre una carpeta.

Cada comando abre una sesión nueva y cierra al terminar; no hay demonio, caché ni estado local.

Notas

  • send guarda una copia en la carpeta de enviados vía IMAP (se omite con --no-record).
  • move/delete usan UID MOVE si el servidor lo soporta, con fallback a COPY + \Deleted + EXPUNGE.
  • TLS es siempre obligatorio; no hay conexiones en texto plano.

Desarrollo

cargo test          # tests unitarios + integración del CLI, sin servidor
cargo clippy --all-targets -- -D warnings
cargo fmt --check

Licencia

MIT