Files
fn_registry/python/functions/infra/imap_fetch_message.md
T
egutierrez 763e06c127 feat(browser): auto-commit con 178 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-20 18:22:23 +02:00

4.3 KiB

name, kind, lang, domain, version, purity, signature, description, tags, params, output, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags params output uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path file_path
imap_fetch_message function py infra 1.0.0 impure def imap_fetch_message(conn, uid: int, mark_seen: bool = False) -> dict Descarga y parsea un mensaje IMAP por UID a un dict estructurado. Sobre una conexion imaplib viva (de imap_connect) ejecuta conn.uid('FETCH', uid, '(BODY.PEEK[])') si mark_seen=False (NO marca leido) o '(RFC822)' si True (marca \Seen), parsea con email.message_from_bytes y extrae from/to/cc/subject/date/message_id (cabeceras RFC 2047 decodificadas a Unicode con decode_header), body_text (text/plain) y body_html (text/html) respetando el charset de cada parte, y attachments como lista de {filename, content_type, size_bytes} SIN bajar el binario completo. Maneja multipart y mensajes simples. Devuelve {status:'ok', message:{...}} o {status:'error', error}. Nunca lanza.
email
imap
infra
parse
network
name desc
conn Objeto imaplib.IMAP4[_SSL] vivo y autenticado, producido por imap_connect. None devuelve status error.
name desc
uid UID del mensaje (de imap_search). NO numero de secuencia. No-entero devuelve status error.
name desc
mark_seen False (default) usa BODY.PEEK[] y NO marca el mensaje como leido. True usa RFC822 y lo marca \Seen.
dict de estado. En exito {status:'ok', message:{uid:int, from:str, to:str, cc:str, subject:str, date:str, message_id:str, body_text:str (text/plain concatenado), body_html:str (text/html concatenado), attachments:[{filename:str, content_type:str, size_bytes:int}]}}: cabeceras decodificadas de RFC 2047 a Unicode; cuerpos decodificados respetando el charset declarado. En fallo (conn None, uid no-entero o inexistente, FETCH no OK) {status:'error', error: str}.
false error_py_core
false
python/functions/infra/imap_fetch_message.py

Ejemplo

import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from infra import imap_connect, imap_search, imap_fetch_message

c = imap_connect("imap.gmail.com", 993, "gutierenmanuel15@gmail.com", "abcd efgh ijkl mnop")
conn = c["conn"]

# Localiza no leidos y lee el primero SIN marcarlo como leido (PEEK)
found = imap_search(conn, criteria="UNSEEN")
if found["uids"]:
    res = imap_fetch_message(conn, found["uids"][0], mark_seen=False)
    m = res["message"]
    print(m["from"])          # 'Soporte <soporte@banco.es>'
    print(m["subject"])       # 'Tu factura de junio'  (acentos ya decodificados)
    print(m["date"])
    print(m["body_text"][:200])
    for att in m["attachments"]:
        print(att["filename"], att["content_type"], att["size_bytes"])

conn.logout()

Cuando usarla

Usala como ultimo paso del flujo de lectura (connect -> search -> fetch) cuando ya tienes un UID y quieres el contenido del mensaje normalizado: remitente, asunto, fecha, cuerpo en texto/HTML y la lista de adjuntos con sus metadatos. Deja mark_seen=False para previsualizar sin alterar el estado leido/no-leido del buzon (util en monitores que no deben "tocar" la bandeja del usuario).

Gotchas

  • Funcion impura: hace red sobre el conn vivo. Nunca lanza: comprueba status. El conn lo provee imap_connect; este grupo se compone en un mismo proceso Python (heredoc), no por fn run.
  • Espera UID (de imap_search), NO numero de secuencia. Pasar un seq devuelve el mensaje equivocado o ninguno.
  • mark_seen=False usa BODY.PEEK[] y NO marca leido; mark_seen=True usa RFC822 y SI marca \Seen. Elige segun si quieres que el usuario vea el correo como ya leido.
  • attachments lista metadatos (filename, content_type, size_bytes) pero NO incluye el binario para no inflar el resultado; size_bytes se mide decodificando el payload de esa parte. Para bajar un adjunto, haz un FETCH parcial aparte por su seccion.
  • Charsets: cada parte de texto se decodifica con el charset declarado, con fallback a utf-8 y latin-1; las cabeceras (Subject, From, ...) se decodifican de RFC 2047 (=?UTF-8?B?...?=). Mensajes mal etiquetados pueden mostrar caracteres de reemplazo en vez de fallar.
  • Mensajes muy grandes (adjuntos pesados) descargan el RFC822 completo: ten en cuenta el ancho de banda y la memoria.
  • Cierra con conn.logout() al terminar (responsabilidad del caller).