Correo electrónicoRFC 822 formato de mensaje

La especificación de RFC 822 de Internet (biblioteca de análisis RFC 822) define un formato de mensaje electrónico que consta de campos de encabezado y un cuerpo de mensaje opcional. 

Los campos de encabezado contienen información sobre el mensaje, como el remitente, el destinatario y el asunto. Si se incluye un cuerpo del mensaje, se separa de los campos del encabezado por una línea vacía (\ r \ n).

El siguiente ejemplo ilustra un mensaje en el formato de mensaje RFC 822:

Rfc formato de mensaje enviado

Correo Electrónico (RFC 822, MIME, SMTP, POP3 e IMAP)

El formato de mensaje RFC 822 es la base para otros formatos de mensaje. El siguiente ejemplo ilustra el formato de artículo / mensaje de Usenet especificado por RFC 850:

1. Estructura general

Correo Electrónico RFC822 MIME SMTP POP3 O IMAP
  • 1 . Juan le escribe un mensaje a María con formato específico RFC 822. Gracias a las extensiones MIME puede adjuntarle una foto (jpg) y una serenata escrita especialmente para ella (wav). El mail lo escribe en su computadora con algún programa para este fin que llamaremos User Agent (UA). (elm, pico, Mozilla, etc.)
  • 2. El mensaje se envía utilizando el protocolo SMTP (sobre TCP) al servidor de correo (Mail Tranfer Agent, MTA 1) en el cual Juan tiene su mailbox. La dirección de mail de Juan define unívocamente su mailbox.
  • 3. El mensaje va pasando de MTA en MTA hasta alcanzar servidor de correo donde María posee su mailbox (MTA 3). Los servidores de correo intermedios funcionana como Gateway de mails, rutean el mensaje como los routers en IP. Cada servidor de correo debe realizar una consulta al DNS para descubrir el servidor de correo del dominio del Maria ([email protected]). O sea pregunta al DNS por los registros MX asociados al dominio de la dirección de mail.
  • 4. Una vez que el mail llega al mailbox destino, María lo lee con su UA. El mismo puede estar basado en los protocolos POP3, IMAP, o bien María podría conectarse directamente a la máquina que posee su casilla de correo y acceder con elm o pico.

2. Formato del Mensaje RFC-822 y extensión MIME (Multi Purpose Internet Mail)

El encabezado del mensaje está compuesto por campos. Algunos se completan de forma automática por el UA: From, Date, Received.

Otros son completados por el usuario: To, Subject, Bcc. Los campos Received sólo aparecen en el mail al llegar al destino, pues contiene el nombre, IP y otros datos que son completados por los MTA por los que pasó el mensaje.

El campo Bcc sólo se ve en el mail emisor, o sea en el mail que queda copiado en la carpeta “Mensajes Enviados”. El RFC 822 en principio sólo soportaba TEXTO en el cuerpo del mensaje.

Para poder enviar otro tipo de formatos se extendio dicho RFC con las extensiones MIME. Como el protocolo SMTP sólo permite enviar mensajes escritos en ASCII, MIME permite codificar en ASCII objetos “arbitrarios”, de otro tipo como ser binario, imágenes, etc.

Dichas extensiones hacen que aparezcan nuevos campos en el encabezado de un mail. Algunos de los campos son:

1. Mime Version:

Versión de MIME utilizado por el UA.

2. Content-Type: Tipo/Subtipo; boundary=»—-XXX—»

Este campo define el Tipo y Subtipo de los objetos que se adjuntan al mail. En caso de adjuntar más de un objeto al mail se agrega el campo “boundary” donde se definirá el delimitador entre cada objeto del mensaje.

Algunos de los tipos que se pueden definir son:

Para cada objeto que se puede codificar con MIME existe un RFC que define su codificación.

3. Content-transfering-encoding:

Este campo indica el método con el que fue codificado el objeto a enviar. Por ejemplo: base64, 7bit, 8bit, etc.

En caso de adjuntar más de un objeto, se dijo que se separan por el delimitador indicado en “boundary”. Luego en cada sección existirán los campos MIME: Content-Type, Mime version y Content-Transfer-encoding.

3. Detalle del protocolo SMTP (Simple Mail Transfer protocol) RFC-821

El protocolo SMTP corresponde a un modelo Cliente/Servidor. Inicialmente el cliente establece una conexión confiable TCP (Three way handshaking) al puerto TCP número 25 del servidor de correo.

Luego se habla el protocolo SMTP. O sea se intercambian mensajes definidos en el protocolo a través de esa conexión TCP.

Algunos de los mensajes que envía el cliente son:

  • HELO hostname EL cliente se presenta con el nombre de máquina.
  • MAIL FROM: Dirección de correo del que envía el mensaje.
  • RCPT TO: Dirección de correo destino. Si se desea enviar el mismo mail a varios destinatarios, esta instrucción se puede dar más de una vez seguida.
  • DATA (presionar enter) Indica que a partir de aquí empieza el mensaje.
  • . (un punto pegado al margen y seguido de un enter) Indica fin del mensaje. Si se desea enviar más de un mail a través de una conexión TCP, a continuación del comando “. “ se puede comenzar nuevamente la secuencia: MAIL FROM, RCPT TO, DATA, “.”.
  • TURN El cliente pasa a ser el servidor, y el servidor se convierte en cliente. Este comando fue poco utilizado por ser poco seguro.
  • QUIT Finaliza la conexión TCP. El servidor responde con el mismo tipo de respuestas que utilizan los protocolos FTP, http, entre otros. Las mismas se dividen por categorías:
  • 2XX, para una respuesta satisfactoria
  • 3XX, para una respuesta temporal afirmativa
  • 4XX, para una respuesta de error, pero se espera a que se repita la instrucción
  • 5XX, para una respuesta de error. Se muestra un ejemplo de una conexión SMTP. Con el comando TELNET el CLIENTE inicia una conexión TCP al puerto 25 donde atiende un servidor SMTP. Una vez finalizado el 3 way handshaking el servidor en este caso responde “220 smtp-1.dc.uba.ar ESMTP”.

Sinopsis

#include <rfc822.h>

#include <rfc2047.h>

cc ... -lrfc822

Descripción de la biblioteca de RFC822

La biblioteca rfc822 proporciona funciones para analizar encabezados de correo electrónico en el formato RFC 822. Esta biblioteca también incluye algunas funciones para ayudar a codificar y descodificar texto de 8 bits, como lo define el RFC 2047.

El formato utilizado por los encabezados de correo electrónico para codificar la información del remitente y el destinatario se define mediante RFC 822 (y su sucesor, RFC 2822 ). El formato permite que la dirección de correo electrónico real y el nombre del remitente / destinatario se expresen juntos, por ejemplo: John Smith <[email protected]>

El propósito principal de la biblioteca rfc822 es:

1) Analizar una cadena de texto que contiene una lista de direcciones con formato RFC 822 en sus componentes lógicos: nombres y direcciones de correo electrónico.

2) Acceder a esos componentes individuales.

3) Permita algunas modificaciones limitadas de la estructura analizada y luego vuelva a convertirla en una cadena de texto.

Tokenizing un encabezado de correo electrónico

struct rfc822t * tokens = rfc822t_alloc_new (const char * header,
                void (* err_func) (const char *, int, void *),
                void * func_arg);

void rfc822t_free (tokens);

La rfc822t_alloc_newfunción () (supera rfc822t_alloc(), que ahora está obsoleta) acepta un correo electrónico headery lo analiza en tokens individuales. Esta función asigna y devuelve un puntero a unaestructura rfc822t , que más tarde usa rfc822a_alloc() para extraer direcciones individuales de estos tokens.

Si el err_funcargumento, si no es NULL, es un puntero a una función de devolución de llamada. Se llama a la función en el caso de que el encabezado del correo electrónico esté dañado hasta el punto de que ni siquiera se pueda analizar. Esta es una instancia rara: la mayoría de las formas de corrupción siguen siendo válidas al menos en el nivel léxico. La única vez que se informa de este error es en el caso de paréntesis, paréntesis angulares o comillas que no coinciden. La función de devolución de llamada recibe el headerpuntero, un índice al error de sintaxis en la cadena del encabezado y el func_argargumento.

Las semánticas de err_funcestán sujetas a cambios. Se recomienda dejar este argumento como NULL en la versión actual de la biblioteca.

rfc822t_alloc() devuelve un puntero a una estructura rfc822t asignada dinámicamente . Se devuelve un puntero NULL si no hay suficiente memoria para asignar esta estructura. La rfc822t_freefunción () destruye la estructura rfc822t y libera toda la memoria asignada dinámicamente.

Nota

Hasta que rfc822t_freese llame (), el contenido de headerNO DEBE ser destruido o alterado de ninguna manera. Los contenidos de headerno están modificados por rfc822t_alloc(), sin embargo, la estructura rfc822t contiene punteros a partes de los suministrados header, y deben permanecer válidos.

Extraer direcciones de correo electrónico

struct rfc822a * addrs = rfc822a_alloc (struct rfc822t * tokens);

void rfc822a_free (addrs);

La rfc822a_allocfunción () devuelve una estructura rfc822a asignada dinámicamente , que contiene direcciones individuales que se analizaron lógicamente desde una estructura rfc822t . Larfc822a_allocfunción () devuelve NULL si no había memoria suficiente para asignar la estructura rfc822a . La rfc822a_freefunción () destruye la función rfc822a y libera toda la memoria asignada dinámicamente asociada. La estructura rfc822t pasada a rfc822a_alloc() no debe destruirse antes de que rfc822a_free() destruya la estructura rfc822a .

La estructura rfc822a tiene los siguientes campos:

estructura rfc822a {
        struct rfc822addr * addrs;
        int naddrs;
};

El naddrscampo proporciona el número de estructuras rfc822addr a las que apunta addrs, que es una matriz. Cada estructura rfc822addr representa una dirección que se encuentra en el encabezado original del correo electrónico o el contenido de un «azúcar sintáctica» heredado . Por ejemplo, el siguiente es un encabezado de correo electrónico válido:

Para: lista de destinatarios: [email protected], [email protected];

Por lo general, todo esto, excepto » To:«, es tokenizado por rfc822t_alloc(), luego analizado por rfc822a_alloc(). » recipient-list:» y el punto y coma final es una especificación de lista de correo heredada que ya no se usa de forma generalizada, pero aún debe ser considerada. La estructura rfc822a resultante tendrá cuatro estructuras rfc822addr : una para » recipient-list:«; uno para cada dirección; y uno para el punto y coma final. Cada estructura rfc822a tiene los siguientes campos:

estructura rfc822addr {
        struct rfc822token * tokens;
        struct rfc822token * nombre;
};

Si tokenses un puntero nulo, esta estructura representa una parte no direccionada del encabezado original, como » recipient-list:» o un punto y coma. De lo contrario, apunta a una estructura que representa la dirección de correo electrónico en forma de token.

nameo bien apunta a la forma en token de una parte sin dirección del encabezado original, o a una forma en token del nombre del destinatario. nameserá NULL si no se proporcionó el nombre del destinatario. Para la siguiente dirección: Tom Jones <[email protected]>– el tokenscampo apunta a la forma «tokenizada [email protected]«, y nameapunta a la forma «tokenizada Tom Jones«.

Cada estructura rfc822token contiene los siguientes campos:

estructura rfc822token {
        struct rfc822token * next;
        token de int
        const char * ptr;
        int len
};

El nextpuntero crea una lista enlazada de todos los tokens en este nombre o dirección. Los valores posibles para el tokencampo son:0x00

Este es un átomo simple: una secuencia de caracteres no especiales que está delimitada por espacios en blanco o caracteres especiales (ver más abajo).0x22

El valor de la cita ascii – esta es una cadena entrecomillada.Paréntesis abiertos: ‘(‘

Este es un comentario de estilo antiguo. Una forma obsoleta de direccionamiento de correo electrónico utiliza, por ejemplo, » [email protected] (John Smith)» en lugar de » John Smith <[email protected]>«. Esta notación de estilo antiguo definía el contenido entre paréntesis como comentarios arbitrarios. El rfc822token con el tokenconjunto a ‘(‘ se crea para los contenidos de todo el comentario.Símbolos: ‘<‘, ‘>’, ‘@’ y muchos otros

Los valores posibles restantes de tokenincluyen todos los caracteres en los encabezados RFC 822 que tienen un significado especial.

Cuando una estructura rfc822token no representa un carácter especial, el ptrcampo apunta a una cadena de texto que da su contenido. Los contenidos NO están terminados en nulo, el len campo contiene el número de caracteres incluidos. La macro rfc822_is_atom (token) indica si ptrlense usa para lo dado token. Currently rfc822_is_atom() devuelve true si tokenes un byte cero, ‘ "‘, o ‘ (‘.

Tenga en cuenta que es posible que lensea ​​cero. Esto sucede con las direcciones nulas utilizadas como direcciones de retorno para las notificaciones de estado de entrega.

Trabajar con direcciones de correo electrónico

void rfc822_deladdr (struct rfc822a * addrs, índice int);

void rfc822tok_print (const struct rfc822token * list,
        void (* func) (char, void *), void * func_arg);

void rfc822_print (const struct rfc822a * addrs,
        void (* print_func) (char, void *),
        void (* print_separator) (const char *, void *), void * callback_arg);
 
void rfc822_addrlist (const struct rfc822a * addrs,
                void (* print_func) (char, void *),
                void * callback_arg);
 
void rfc822_namelist (const struct rfc822a * addrs,
                void (* print_func) (char, void *),
                void * callback_arg);

void rfc822_praddr (const struct rfc822a * addrs,
                índice de int
                void (* print_func) (char, void *),
                void * callback_arg);

void rfc822_prname (const struct rfc822a * addrs,
                índice de int
                void (* print_func) (char, void *),
                void * callback_arg);

void rfc822_prname_orlist (const struct rfc822a * addrs,
                índice de int
                void (* print_func) (char, void *),
                void * callback_arg);

char * rfc822_gettok (const struct rfc822token * list);
char * rfc822_getaddrs (const struct rfc822a * addrs);
char * rfc822_getaddr (const struct rfc822a * addrs, índice int);
char * rfc822_getname (const struct rfc822a * addrs, índice int);
char * rfc822_getname_orlist (const struct rfc822a * addrs, índice int);

char * rfc822_getaddrs_wrap (const struct rfc822a *, int);

Estas funciones se utilizan para trabajar con direcciones individuales que son analizadas por rfc822a_alloc().

rfc822_deladdr() elimina una única estructura rfc822addr , que indexse proporciona, de la matriz de direcciones en rfc822addr . naddrsSe decrementa en uno.

rfc822tok_print() convierte un tokenizado listde objetos rfc822token en una cadena de texto. La función de devolución de llamada,, funcse llama un carácter a la vez, para cada carácter en los objetos de token. Un puntero arbitrario,, func_argse pasa sin cambios como el argumento adicional a la función de devolución de llamada. rfc822tok_print() Normalmente no es la función más conveniente y eficiente, pero tiene sus usos.

rfc822_print() toma una estructura rfc822a completa y usa las funciones de devolución de llamada para imprimir las direcciones contenidas, en su forma original, separadas por comas. La función señalada por print_funcse utiliza para imprimir cada dirección individual, un carácter a la vez. Entre las direcciones, print_separatorse llama a la función para imprimir el separador de direcciones, generalmente la cadena «,». El callback_argargumento se pasa sin cambios, como un argumento adicional a estas funciones.

Las funciones rfc822_addrlist() y rfc822_namelist() también imprimen el contenido de toda la estructura rfc822a , pero de una manera diferente. rfc822_addrlist() imprime solo las direcciones de correo electrónico reales, no los nombres ni los comentarios de los destinatarios. Cada dirección de correo electrónico va seguida de un carácter de nueva línea. rfc822_namelist() imprime solo los nombres o comentarios, seguido de nuevas líneas.

Las funciones rfc822_praddr() y rfc822_prname() son como rfc822_addrlist() y rfc822_namelist(), excepto que imprimen un solo nombre o dirección en la estructura rfc822a , dada su index. Las funciones rfc822_gettok(), rfc822_getaddrs(), rfc822_getaddr() y rfc822_getname() son equivalentes a rfc822tok_print(), rfc822_print(), rfc822_praddr() y rfc822_prname(), pero, en lugar de usar un puntero de función de devolución de llamada, estas funciones escriben la salida en un búfer asignado dinámicamente. Ese tampón debe ser destruido por free(3) después de su uso. Estas funciones devolverán un puntero nulo en caso de que no se pueda asignar memoria para el búfer.

rfc822_prname_orlist() es similar a rfc822_prname(), excepto que también imprimirá la sintaxis de la lista de grupos RFC822 heredada (que también se analiza con rfc822a_alloc()). rfc822_praddr() imprimirá una cadena vacía para un índice que corresponde a un nombre de lista de grupo (o punto y coma finalizado). rfc822_prname() también imprimirá una cadena vacía. rfc822_prname_orlist() en cambio, imprimirá el nombre de la lista de grupos o una sola cadena «;». rfc822_getname_orlist() en lugar de eso lo guardará en un búfer asignado dinámicamente.

La función rfc822_getaddrs_wrap() es similar a rfc822_getaddrs(), excepto que el texto generado se ajusta en o alrededor de la columna 73, utilizando caracteres de nueva línea.

Trabajando con fechas

time_t timestamp = rfc822_parsedt (const char * datestr)
const char * datestr = rfc822_mkdate (time_t timestamp);
void rfc822_mkdate_buf (time_t timestamp, char * buffer);

Estas funciones convierten las marcas de tiempo y las fechas expresadas en el Date:formato de encabezado de correo electrónico.

rfc822_parsedt() devuelve la marca de tiempo correspondiente a la cadena de fecha dada (0 si hubo un error de sintaxis).

rfc822_mkdate() devuelve una cadena de fecha correspondiente a la marca de tiempo dada. rfc822_mkdate_buf() escribe la cadena de fecha en el búfer dado, que debe ser lo suficientemente grande para acomodarla.

Trabajar con encabezados codificados MIME de 8 bits

int error = rfc2047_decode (const char * text,
                int (* callback_func) (const char *, int, const char *, void *),
                void * callback_arg);
 
extern char * str = rfc2047_decode_simple (const char * text);
 
extern char * str = rfc2047_decode_enhanced (const char * text,
                const char * charset);
 
void rfc2047_print (const struct rfc822a * a,
        const char * charset,
        void (* print_func) (char, void *),
        void (* print_separator) (const char *, void *), void *);

 
char * buffer = rfc2047_encode_str (const char * string,
                const char * charset);
 
int error = rfc2047_encode_callback (const char * string,
        const char * charset,
        int (* func) (const char *, size_t, void *),
        void * callback_arg);
 
char * buffer = rfc2047_encode_header (const struct rfc822a * a,
        const char * charset);

Estas funciones proporcionan lógica adicional para codificar o decodificar contenido de 8 bits en encabezados RFC 822 de 7 bits, como se especifica en RFC 2047.

rfc2047_decode() es una función básica de decodificación RFC 2047. Recibe un puntero a un texto codificado de 7bit RFC 2047 y una función de devolución de llamada. La función de devolución de llamada se llama repetidamente. Cada vez que se le llama recibe un trozo de texto decodificado. Los argumentos son: un puntero a un fragmento de texto, número de bytes en el fragmento de texto, seguido de un puntero al conjunto de caracteres del fragmento de texto. El puntero del conjunto de caracteres es NULL para partes del texto original que no están codificadas con RFC 2047.

La función de devolución de llamada también recibe callback_arg, como su último argumento. Si la función de devolución de llamada devuelve un valor distinto de cero, rfc2047_decode() termina, devolviendo ese valor. De lo contrario, rfc2047_decode() devuelve 0 después de una decodificación exitosa. rfc2047_decode() devuelve -1 si no pudo asignar suficiente memoria.

rfc2047_decode_simple() y rfc2047_decode_enhanced() son alternativas a rfc2047_decode() que renuncian a una función de devolución de llamada y devuelven el texto descodificado en un búfer de memoria asignado dinámicamente. El buffer debe ser free(3) -ed después de su uso. rfc2047_decode_simple() descarta todas las especificaciones del conjunto de caracteres y simplemente descodifica cualquier texto de 8 bits. rfc2047_decode_enhanced() es un compromiso para descartar toda la información del conjunto de caracteres. El conjunto de caracteres locales que se está utilizando se especifica como el segundo argumento para rfc2047_decode_enhanced(). Cualquier texto codificado en RFC 2047 en un conjunto de caracteres diferente será prefijado por el nombre del conjunto de caracteres, entre paréntesis, en la salida resultante.

rfc2047_decode_simple() y rfc2047_decode_enhanced() devuelven un puntero nulo si no pueden asignar suficiente memoria.

La rfc2047_printfunción () es equivalente a rfc822_print(), seguida de rfc2047_decode_enhanced() en el resultado. Las funciones de devolución de llamada se utilizan de manera idéntica, excepto que reciben texto que ya está descodificado.

La función rfc2047_encode_str() toma una stringcharset siendo el nombre del conjunto de caracteres local, luego codifica cualquier porción de 8 bits del stringuso de la codificación RFC 2047.rfc2047_encode_str() devuelve un búfer asignado dinámicamente con el resultado, que debe ser free(3) -ed después del uso, o NULL si no había suficiente memoria para asignar el búfer.

La función rfc2047_encode_callback() es similar a rfc2047_encode_str() excepto que la función de devolución de llamada se llama repetidamente para recibir la cadena de codificación. Cada invocación de la función de devolución de llamada recibe un puntero a una parte del texto codificado, el número de caracteres en esta parte y callback_arg.

La función rfc2047_encode_header() es básicamente equivalente a rfc822_getaddrs(), seguida de rfc2047_encode_str();

Trabajar con sujetos

char * basesubj = rfc822_coresubj (const char * subj);

char * basesubj = rfc822_coresubj_nouc (const char * subj);

Esta función toma el contenido del encabezado de materia y devuelve el encabezado de materia «central» que se utiliza en la especificación de la función IMPRE ROSCA. Esta función está diseñada para eliminar todos los artefactos de la línea de asunto que podrían haberse agregado en el proceso de reenvío o respuesta a un mensaje. Actualmente, rfc822_coresubj() realiza las siguientes transformaciones:Espacio en blanco

Se eliminan los espacios en blanco iniciales y finales. Los caracteres de espacio en blanco consecutivos se contraen en un solo carácter de espacio en blanco. Todos los caracteres de espacio en blanco son reemplazados por un espacio.Re :, (fwd) [foo]

Estos artefactos (y varios otros) se eliminan de la línea de asunto.

Tenga en cuenta que esta función NO realiza decodificación MIME. Para implementar IMAP THREAD, es necesario llamar algo como rfc2047_decode() antes de llamar rfc822_coresubj().

Esta función devuelve un puntero a un búfer asignado dinámicamente, que debe ser free(3) después de su uso.

rfc822_coresubj_nouc() es como rfc822_coresubj(), excepto que el sujeto no se convierte a mayúsculas.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos requeridos están marcados *

Publicar comentario