763e06c127
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.3 KiB
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. |
|
|
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
connvivo. Nunca lanza: compruebastatus. Elconnlo proveeimap_connect; este grupo se compone en un mismo proceso Python (heredoc), no porfn run. - Espera UID (de
imap_search), NO numero de secuencia. Pasar un seq devuelve el mensaje equivocado o ninguno. mark_seen=FalseusaBODY.PEEK[]y NO marca leido;mark_seen=TrueusaRFC822y SI marca\Seen. Elige segun si quieres que el usuario vea el correo como ya leido.attachmentslista metadatos (filename,content_type,size_bytes) pero NO incluye el binario para no inflar el resultado;size_bytesse 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).