Construyendo un sistema de archivo de correo electrónico: los desafíos y, por supuesto, la solución – Parte 1

Jeff Goldstein

4 feb 2019

Correo electrónico

1 min read

Construyendo un sistema de archivo de correo electrónico: los desafíos y, por supuesto, la solución – Parte 1

Puntos clave

    • El archivo de correos electrónicos es cada vez más esencial para entornos regulatorios, de cumplimiento y auditoría.

    • SparkPost no almacena cuerpos de correo electrónico, pero su función de Archive permite a los remitentes recibir mensajes duplicados que reflejan enlaces de seguimiento y contenido.

    • Los cuerpos de correo electrónico pueden almacenarse en Amazon S3, mientras que los metadatos de eventos de mensajes pueden almacenarse en MySQL para consultas y referencias cruzadas.

    • Los eventos de mensajes de SparkPost proporcionan registros de actividades detallados (rebotes, entregas, clics, aperturas, bajas, quejas y más).

    • Las copias de archivo solo se generan al enviar correos electrónicos a través de SMTP.

    • Los eventos de mensajes para correos electrónicos originales, archivados, CC y CCO comparten un transmission_id común.

    • El Inbound Email Relay puede ingerir mensajes archivados pero no incluye el transmission_id, creando un desafío de vinculación de datos.

    • Insertar un identificador único oculto (UID) en el cuerpo del mensaje cierra esa brecha y vincula el contenido entrante con los registros salientes.

    • La combinación de correos electrónicos archivados + eventos de mensajes permite construir un sistema de archivo auditable y buscable.

    • El proyecto a largo plazo incluye lanzamientos de código para almacenar correos electrónicos archivados en S3 y registrar datos de eventos en MySQL.

    • La aplicación final permitirá buscar, ver y reconciliar fácilmente el contenido del correo electrónico con todo el historial de eventos relacionados.

    • Ideal para industrias con altos requisitos de cumplimiento que necesitan visibilidad completa en cada mensaje enviado.

Destacados de Q&A

  • ¿Por qué construir tu propio sistema de archivado de email?

    Las industrias reguladas a menudo requieren almacenamiento a largo plazo tanto del cuerpo del email como de todos los registros de eventos asociados. SparkPost no almacena los cuerpos de los mensajes, por lo que construir un sistema personalizado asegura el cumplimiento, la auditoría y la visibilidad.

  • ¿Cómo se obtiene una copia exacta del correo electrónico original enviado?

    La Archive feature de SparkPost envía una copia de cada correo electrónico saliente a las direcciones de archivo designadas, preservando todos los enlaces codificados y comportamientos de seguimiento.

  • ¿Por qué no puedes capturar el cuerpo del correo electrónico antes de enviar?

    La captura previa al envío no incluye las modificaciones de SparkPost (seguimiento de apertura, seguimiento de clics, codificación de enlaces). Usar copias del archivo garantiza que la versión guardada coincida exactamente con lo que reciben los destinatarios.

  • ¿SparkPost archiva correos electrónicos automáticamente?

    No. SparkPost no almacena cuerpos de mensajes. Las copias de archivo deben solicitarse especificando direcciones de archivo durante la inyección SMTP.

  • ¿Qué se almacena dónde en este sistema de archivado?

    • Cuerpo del correo electrónico → Amazon S3

    • Registros de eventos de mensajes → MySQL
      Esta separación admite búsqueda rápida, consultas estructuradas y almacenamiento de objetos económico.

  • ¿Cuánto tiempo conserva SparkPost los datos de eventos?

    SparkPost almacena eventos de mensajes durante 10 días. Después de eso, los datos deben ser ingeridos a través de webhook o consultados y almacenados en otro lugar.

  • ¿Qué eventos de mensaje están disponibles?

    SparkPost actualmente expone 14 eventos, incluidos entregas, rebotes, clics, aperturas, rechazos, problemas de política, quejas de spam, cancelaciones de suscripción y más.

  • ¿Qué identificadores conectan todos los eventos?

    Todos los mensajes salientes (original, archivo, CC, BCC) comparten el mismo transmission_id. El correo electrónico original y el de archivo también comparten el mismo message_id.

  • ¿Por qué es un desafío el procesamiento inbound?

    El Inbound Email Relay de SparkPost convierte el correo electrónico entrante en JSON, pero este JSON no incluye transmission_id. Sin datos adicionales, la copia entrante no se puede vincular a su historial de registro saliente.

  • ¿Cómo conectas los emails de archivo entrantes a los eventos de mensajes salientes?

    Inserta un identificador único (UID) oculto en el cuerpo del correo electrónico y pasa el mismo UID en los metadatos. Este UID se convierte en la referencia compartida a través de los registros entrantes y salientes.

  • ¿Cómo ayuda Inbound Email Relay a automatizar el archivo?

    Recibe correos electrónicos de archivo enviados a su dominio de archivo, los analiza en JSON estructurado y los envía a su aplicación a través de webhook, permitiendo la extracción y almacenamiento automatizados.

  • ¿Cuál es la visión a largo plazo del proyecto?

    Una aplicación completa que:

    • Almacena correos electrónicos archivados en S3

    • Almacena todos los registros de eventos en MySQL

    • Permite a los usuarios buscar correos electrónicos

    • Muestra el correo electrónico original y cada evento asociado en una interfaz unificada

Hace aproximadamente un año escribí un blog sobre cómo recuperar copias de correos electrónicos para archivo y visualización, pero no abordé el almacenamiento real del correo electrónico o datos relacionados, y recientemente escribí un blog sobre cómo almacenar todos los datos de eventos (es decir, cuándo se envió el correo electrónico, aperturas, clics, rebotes, cancelaciones de suscripción, etc.) en un correo electrónico con el fin de realizar una auditoría, pero elegí no crear ningún código de soporte.

Con el aumento del uso del correo electrónico en entornos regulatorios, he decidido que es hora de iniciar un nuevo proyecto que reúna todo esto con ejemplos de código sobre cómo almacenar el cuerpo del correo electrónico y todos sus datos asociados. Durante el próximo año, seguiré construyendo sobre este proyecto con el objetivo de crear una aplicación funcional de almacenamiento y visualización para correos electrónicos archivados y toda la información de registro producida por SparkPost. SparkPost no tiene un sistema que archive el cuerpo del correo electrónico, pero hace que la creación de una plataforma de archivo sea bastante fácil.

En esta serie de blogs, describiré el proceso por el que pasé para almacenar el cuerpo del correo electrónico en S3 (Amazon’s Simple Store Service) y todos los datos de registro relevantes en MySQL para una fácil referencia cruzada. Para sistemas de archivo de producción que requieren estrategias robustas de respaldo de base de datos, considere implementar un proceso de respaldo y restauración de PostgreSQL integral para asegurar que sus datos de archivo estén adecuadamente protegidos. En última instancia, este es el punto de partida para construir una aplicación que permitirá una fácil búsqueda de correos electrónicos archivados, luego mostrando esos correos junto con los datos de eventos (registro). El código para este proyecto se puede encontrar en el siguiente repositorio de GitHub: PHPArchivePlatform en GitHub

Esta primera entrada de la serie de blogs va a describir el desafío y establecer una arquitectura para la solución. El resto de los blogs detallarán las porciones de la solución junto con ejemplos de código.

El primer paso en mi proceso fue averiguar cómo iba a obtener una copia del correo electrónico enviado al destinatario original. Para obtener una copia del cuerpo del correo electrónico, necesitas:


Opciones de Captura de Cuerpo de Correo Electrónico

Método

Quién crea la copia

Refleja cambios de seguimiento

Amigable para automatización

Usado en esta solución

Capturar antes de enviar

Aplicación

❌ No

✅ Sí

El servidor de correo almacena copia

Servidor de correo

✅ Sí

❌ Limitada

Función de Archivo de SparkPost

SparkPost

✅ Sí

✅ Sí


  1. Capturar el cuerpo del correo electrónico antes de enviar el correo

  2. Hacer que el servidor de correo almacene una copia

  3. Permitir que el servidor de correo cree una copia para almacenar

Si el servidor de correo está agregando elementos como el seguimiento de enlaces o apertura, no puedes usar #1 porque no reflejará los cambios de seguimiento de apertura/clics.

Eso significa que ya sea el servidor debe almacenar el correo electrónico o de alguna manera ofrecer una copia de ese correo para que lo almacenes. Dado que SparkPost no tiene un mecanismo de almacenamiento para cuerpos de correos electrónicos pero sí tiene una forma de crear una copia del correo, haremos que SparkPost nos envíe un duplicado del correo para almacenarlo en S3.

Esto se hace usando la función de Archivo de SparkPost. La función de Archivo de SparkPost le da al remitente la capacidad de decirle a SparkPost que envíe un duplicado del correo electrónico a una o más direcciones de correo y usar los mismos enlaces de seguimiento y apertura que el original. La documentación de SparkPost define su función de Archivo de la siguiente manera:

Los destinatarios en la lista de archivos recibirán una réplica exacta del mensaje que se envió a la dirección RCPT TO. En particular, los enlaces codificados destinados para el destinatario RCPT TO serán idénticos en los mensajes de archivo

Las únicas diferencias del correo RCPT TO son que algunos de los encabezados serán diferentes ya que la dirección de destino para el correo de archivo es diferente, ¡pero el cuerpo del correo será una réplica exacta!

Si deseas una explicación más profunda aquí hay un enlace a la documentación de SparkPost sobre la creación de copias duplicadas (o de archivo) de un correo electrónico.

Como nota al margen, SparkPost realmente te permite enviar correos electrónicos a direcciones de cc, cco y archivo. Para esta solución, estamos enfocados en las direcciones de archivo.

* Aviso * Los correos electrónicos archivados SOLO se pueden crear cuando se inyectan correos electrónicos en SparkPost a través de SMTP!

Ahora que sabemos cómo obtener una copia del correo original, necesitamos observar los datos de registro que se producen y algunas de las sutilezas dentro de esos datos. SparkPost rastrea todo lo que ocurre en sus servidores y ofrece esa información a ti en forma de eventos de mensajes. Esos eventos se almacenan en SparkPost por 10 días y se pueden extraer del servidor a través de una API RESTful llamada eventos de mensajes, o puedes hacer que SparkPost envíe esos eventos a cualquier número de aplicaciones de recolección que desees. El mecanismo de envío se realiza a través de webhooks y se hace en tiempo real.

Actualmente, hay 14 eventos diferentes que pueden sucederle a un correo electrónico.  Aquí hay una lista de los eventos actuales:

  • Bounce

  • ClickDelay

  • Delivery

  • Generation Failure

  • Generation Rejection

  • Initial Open

  • InjectionLink Unsubscribe

  • List Unsubscribe

  • Open

  • Out of Band

  • Policy RejectionSpam Complaint


* Sigue este enlace para una guía de referencia actualizada para una descripción de cada evento junto con los datos que se comparten para cada evento.

Cada evento tiene numerosos campos que coinciden con el tipo de evento.  Algunos campos como el transmission_id se encuentran en cada evento, pero otros campos pueden ser más específicos del evento; por ejemplo, solo los eventos de apertura y clic tienen información de geolocalización.


Identificadores Usados en el Sistema de Archivado

Identificador

De dónde se origina

Compartido entre

Propósito

Limitación

transmission_id

SparkPost outbound

Original, archivo, cc, cco

Correlaciona todos los eventos de mensajes

No disponible en retransmisión entrante

message_id

SparkPost outbound

Original + archivo

Identifica mensajes individuales

Diferente para cc/cco

UID Oculto

Inyectado por remitente

Salida + entrada

Vincula cuerpo de email archivado a eventos

Debe ser implementado de forma personalizada


Un registro de evento de mensaje muy importante para este proyecto es el transmission_id. Todos los registros de eventos de mensajes para el correo electrónico original, correo archivado y cualquier dirección de cc y cco compartirán el mismo transmission_id.

También hay una entrada común llamada message_id que tendrá el mismo id para cada registro del correo electrónico original y el correo electrónico archivado. Cualquier dirección de cc o cco tendrá su propio id para la entrada message_id .

Hasta ahora esto suena genial y sinceramente bastante fácil, pero ahora es la parte desafiante. Recuerda, para obtener el correo archivado, hacemos que SparkPost envíe un duplicado del correo original a otra dirección de correo que corresponda a alguna bandeja de entrada a la que tengas acceso. Pero para automatizar esta solución y almacenar el cuerpo del correo electrónico, voy a usar otra función de SparkPost llamada Redirección de Correo Electrónico Entrante. Lo que hace, es tomar todos los correos enviados a un dominio específico y procesarlos. Al procesarlos, descompone el correo y crea una estructura JSON que luego se entrega a una aplicación a través de un webhook. Ver Apéndice A para un ejemplo de JSON.

Si prestas mucha atención, notarás que la estructura JSON del relay entrante está perdiendo un campo muy importante; el transmission_id. Mientras que todos los correos electrónicos salientes tienen el transmission_id  con la misma entrada que vincula todos los datos del correo original, archivo, cc, y direcciones cco; SparkPost no tiene forma de saber que el correo capturado por el proceso entrante está conectado a cualquiera de los correos electrónicos salientes. El proceso entrante simplemente sabe que un correo fue enviado a un dominio específico y debe analizar el correo. Eso es todo. Tratará cualquier correo enviado a ese dominio de la misma manera, ya sea una respuesta de un cliente o el correo de archivo enviado desde SparkPost.

Entonces el truco es; ¿cómo pegas los datos salientes al proceso entrante que acaba de capturar la versión archivada del correo electrónico? Lo que decidí hacer es ocultar un id único en el cuerpo del correo electrónico. Cómo se haga esto depende de ti, pero simplemente creé un campo de entrada con la etiqueta oculta activada.

<input name="ArchiveCode" type="hidden" value="<<UID>>">

También agregué ese campo en el bloque de metadatos del encabezado X-MSYS-API que se pasa a SparkPost durante inyección. Este UID oculto será el pegamento para todo el proceso, y es un componente principal del proyecto y será discutido en profundidad en los siguientes posts del blog.

Ahora que tenemos el UID que unirá este proyecto y entendemos por qué es necesario, puedo comenzar a construir la visión del proyecto general y los posts del blog correspondientes.

  1. Captura y almacenamiento del correo de archivo junto con una entrada en la base de datos para búsqueda/indexación

  2. Capturar todos los datos de eventos de mensajes

  3. Crear una aplicación para ver el correo electrónico y todos los datos correspondientes

Aquí hay un diagrama simple del proyecto:

build an email archiving system - diagram


La primera entrega de código cubrirá el proceso de archivo y el almacenamiento del correo en S3, mientras que la segunda entrega de código cubrirá el almacenamiento de todos los datos de registro de eventos de mensajes en MySQL. Puedes esperar las dos primeras entregas de código y entradas del blog a principios de 2019.  Si tienes alguna pregunta o sugerencia, por favor no dudes en pasarlas.

Feliz Envío.
– Jeff


Apéndice A:

JSON file example - email archiving system

Hace aproximadamente un año escribí un blog sobre cómo recuperar copias de correos electrónicos para archivo y visualización, pero no abordé el almacenamiento real del correo electrónico o datos relacionados, y recientemente escribí un blog sobre cómo almacenar todos los datos de eventos (es decir, cuándo se envió el correo electrónico, aperturas, clics, rebotes, cancelaciones de suscripción, etc.) en un correo electrónico con el fin de realizar una auditoría, pero elegí no crear ningún código de soporte.

Con el aumento del uso del correo electrónico en entornos regulatorios, he decidido que es hora de iniciar un nuevo proyecto que reúna todo esto con ejemplos de código sobre cómo almacenar el cuerpo del correo electrónico y todos sus datos asociados. Durante el próximo año, seguiré construyendo sobre este proyecto con el objetivo de crear una aplicación funcional de almacenamiento y visualización para correos electrónicos archivados y toda la información de registro producida por SparkPost. SparkPost no tiene un sistema que archive el cuerpo del correo electrónico, pero hace que la creación de una plataforma de archivo sea bastante fácil.

En esta serie de blogs, describiré el proceso por el que pasé para almacenar el cuerpo del correo electrónico en S3 (Amazon’s Simple Store Service) y todos los datos de registro relevantes en MySQL para una fácil referencia cruzada. Para sistemas de archivo de producción que requieren estrategias robustas de respaldo de base de datos, considere implementar un proceso de respaldo y restauración de PostgreSQL integral para asegurar que sus datos de archivo estén adecuadamente protegidos. En última instancia, este es el punto de partida para construir una aplicación que permitirá una fácil búsqueda de correos electrónicos archivados, luego mostrando esos correos junto con los datos de eventos (registro). El código para este proyecto se puede encontrar en el siguiente repositorio de GitHub: PHPArchivePlatform en GitHub

Esta primera entrada de la serie de blogs va a describir el desafío y establecer una arquitectura para la solución. El resto de los blogs detallarán las porciones de la solución junto con ejemplos de código.

El primer paso en mi proceso fue averiguar cómo iba a obtener una copia del correo electrónico enviado al destinatario original. Para obtener una copia del cuerpo del correo electrónico, necesitas:


Opciones de Captura de Cuerpo de Correo Electrónico

Método

Quién crea la copia

Refleja cambios de seguimiento

Amigable para automatización

Usado en esta solución

Capturar antes de enviar

Aplicación

❌ No

✅ Sí

El servidor de correo almacena copia

Servidor de correo

✅ Sí

❌ Limitada

Función de Archivo de SparkPost

SparkPost

✅ Sí

✅ Sí


  1. Capturar el cuerpo del correo electrónico antes de enviar el correo

  2. Hacer que el servidor de correo almacene una copia

  3. Permitir que el servidor de correo cree una copia para almacenar

Si el servidor de correo está agregando elementos como el seguimiento de enlaces o apertura, no puedes usar #1 porque no reflejará los cambios de seguimiento de apertura/clics.

Eso significa que ya sea el servidor debe almacenar el correo electrónico o de alguna manera ofrecer una copia de ese correo para que lo almacenes. Dado que SparkPost no tiene un mecanismo de almacenamiento para cuerpos de correos electrónicos pero sí tiene una forma de crear una copia del correo, haremos que SparkPost nos envíe un duplicado del correo para almacenarlo en S3.

Esto se hace usando la función de Archivo de SparkPost. La función de Archivo de SparkPost le da al remitente la capacidad de decirle a SparkPost que envíe un duplicado del correo electrónico a una o más direcciones de correo y usar los mismos enlaces de seguimiento y apertura que el original. La documentación de SparkPost define su función de Archivo de la siguiente manera:

Los destinatarios en la lista de archivos recibirán una réplica exacta del mensaje que se envió a la dirección RCPT TO. En particular, los enlaces codificados destinados para el destinatario RCPT TO serán idénticos en los mensajes de archivo

Las únicas diferencias del correo RCPT TO son que algunos de los encabezados serán diferentes ya que la dirección de destino para el correo de archivo es diferente, ¡pero el cuerpo del correo será una réplica exacta!

Si deseas una explicación más profunda aquí hay un enlace a la documentación de SparkPost sobre la creación de copias duplicadas (o de archivo) de un correo electrónico.

Como nota al margen, SparkPost realmente te permite enviar correos electrónicos a direcciones de cc, cco y archivo. Para esta solución, estamos enfocados en las direcciones de archivo.

* Aviso * Los correos electrónicos archivados SOLO se pueden crear cuando se inyectan correos electrónicos en SparkPost a través de SMTP!

Ahora que sabemos cómo obtener una copia del correo original, necesitamos observar los datos de registro que se producen y algunas de las sutilezas dentro de esos datos. SparkPost rastrea todo lo que ocurre en sus servidores y ofrece esa información a ti en forma de eventos de mensajes. Esos eventos se almacenan en SparkPost por 10 días y se pueden extraer del servidor a través de una API RESTful llamada eventos de mensajes, o puedes hacer que SparkPost envíe esos eventos a cualquier número de aplicaciones de recolección que desees. El mecanismo de envío se realiza a través de webhooks y se hace en tiempo real.

Actualmente, hay 14 eventos diferentes que pueden sucederle a un correo electrónico.  Aquí hay una lista de los eventos actuales:

  • Bounce

  • ClickDelay

  • Delivery

  • Generation Failure

  • Generation Rejection

  • Initial Open

  • InjectionLink Unsubscribe

  • List Unsubscribe

  • Open

  • Out of Band

  • Policy RejectionSpam Complaint


* Sigue este enlace para una guía de referencia actualizada para una descripción de cada evento junto con los datos que se comparten para cada evento.

Cada evento tiene numerosos campos que coinciden con el tipo de evento.  Algunos campos como el transmission_id se encuentran en cada evento, pero otros campos pueden ser más específicos del evento; por ejemplo, solo los eventos de apertura y clic tienen información de geolocalización.


Identificadores Usados en el Sistema de Archivado

Identificador

De dónde se origina

Compartido entre

Propósito

Limitación

transmission_id

SparkPost outbound

Original, archivo, cc, cco

Correlaciona todos los eventos de mensajes

No disponible en retransmisión entrante

message_id

SparkPost outbound

Original + archivo

Identifica mensajes individuales

Diferente para cc/cco

UID Oculto

Inyectado por remitente

Salida + entrada

Vincula cuerpo de email archivado a eventos

Debe ser implementado de forma personalizada


Un registro de evento de mensaje muy importante para este proyecto es el transmission_id. Todos los registros de eventos de mensajes para el correo electrónico original, correo archivado y cualquier dirección de cc y cco compartirán el mismo transmission_id.

También hay una entrada común llamada message_id que tendrá el mismo id para cada registro del correo electrónico original y el correo electrónico archivado. Cualquier dirección de cc o cco tendrá su propio id para la entrada message_id .

Hasta ahora esto suena genial y sinceramente bastante fácil, pero ahora es la parte desafiante. Recuerda, para obtener el correo archivado, hacemos que SparkPost envíe un duplicado del correo original a otra dirección de correo que corresponda a alguna bandeja de entrada a la que tengas acceso. Pero para automatizar esta solución y almacenar el cuerpo del correo electrónico, voy a usar otra función de SparkPost llamada Redirección de Correo Electrónico Entrante. Lo que hace, es tomar todos los correos enviados a un dominio específico y procesarlos. Al procesarlos, descompone el correo y crea una estructura JSON que luego se entrega a una aplicación a través de un webhook. Ver Apéndice A para un ejemplo de JSON.

Si prestas mucha atención, notarás que la estructura JSON del relay entrante está perdiendo un campo muy importante; el transmission_id. Mientras que todos los correos electrónicos salientes tienen el transmission_id  con la misma entrada que vincula todos los datos del correo original, archivo, cc, y direcciones cco; SparkPost no tiene forma de saber que el correo capturado por el proceso entrante está conectado a cualquiera de los correos electrónicos salientes. El proceso entrante simplemente sabe que un correo fue enviado a un dominio específico y debe analizar el correo. Eso es todo. Tratará cualquier correo enviado a ese dominio de la misma manera, ya sea una respuesta de un cliente o el correo de archivo enviado desde SparkPost.

Entonces el truco es; ¿cómo pegas los datos salientes al proceso entrante que acaba de capturar la versión archivada del correo electrónico? Lo que decidí hacer es ocultar un id único en el cuerpo del correo electrónico. Cómo se haga esto depende de ti, pero simplemente creé un campo de entrada con la etiqueta oculta activada.

<input name="ArchiveCode" type="hidden" value="<<UID>>">

También agregué ese campo en el bloque de metadatos del encabezado X-MSYS-API que se pasa a SparkPost durante inyección. Este UID oculto será el pegamento para todo el proceso, y es un componente principal del proyecto y será discutido en profundidad en los siguientes posts del blog.

Ahora que tenemos el UID que unirá este proyecto y entendemos por qué es necesario, puedo comenzar a construir la visión del proyecto general y los posts del blog correspondientes.

  1. Captura y almacenamiento del correo de archivo junto con una entrada en la base de datos para búsqueda/indexación

  2. Capturar todos los datos de eventos de mensajes

  3. Crear una aplicación para ver el correo electrónico y todos los datos correspondientes

Aquí hay un diagrama simple del proyecto:

build an email archiving system - diagram


La primera entrega de código cubrirá el proceso de archivo y el almacenamiento del correo en S3, mientras que la segunda entrega de código cubrirá el almacenamiento de todos los datos de registro de eventos de mensajes en MySQL. Puedes esperar las dos primeras entregas de código y entradas del blog a principios de 2019.  Si tienes alguna pregunta o sugerencia, por favor no dudes en pasarlas.

Feliz Envío.
– Jeff


Apéndice A:

JSON file example - email archiving system

Hace aproximadamente un año escribí un blog sobre cómo recuperar copias de correos electrónicos para archivo y visualización, pero no abordé el almacenamiento real del correo electrónico o datos relacionados, y recientemente escribí un blog sobre cómo almacenar todos los datos de eventos (es decir, cuándo se envió el correo electrónico, aperturas, clics, rebotes, cancelaciones de suscripción, etc.) en un correo electrónico con el fin de realizar una auditoría, pero elegí no crear ningún código de soporte.

Con el aumento del uso del correo electrónico en entornos regulatorios, he decidido que es hora de iniciar un nuevo proyecto que reúna todo esto con ejemplos de código sobre cómo almacenar el cuerpo del correo electrónico y todos sus datos asociados. Durante el próximo año, seguiré construyendo sobre este proyecto con el objetivo de crear una aplicación funcional de almacenamiento y visualización para correos electrónicos archivados y toda la información de registro producida por SparkPost. SparkPost no tiene un sistema que archive el cuerpo del correo electrónico, pero hace que la creación de una plataforma de archivo sea bastante fácil.

En esta serie de blogs, describiré el proceso por el que pasé para almacenar el cuerpo del correo electrónico en S3 (Amazon’s Simple Store Service) y todos los datos de registro relevantes en MySQL para una fácil referencia cruzada. Para sistemas de archivo de producción que requieren estrategias robustas de respaldo de base de datos, considere implementar un proceso de respaldo y restauración de PostgreSQL integral para asegurar que sus datos de archivo estén adecuadamente protegidos. En última instancia, este es el punto de partida para construir una aplicación que permitirá una fácil búsqueda de correos electrónicos archivados, luego mostrando esos correos junto con los datos de eventos (registro). El código para este proyecto se puede encontrar en el siguiente repositorio de GitHub: PHPArchivePlatform en GitHub

Esta primera entrada de la serie de blogs va a describir el desafío y establecer una arquitectura para la solución. El resto de los blogs detallarán las porciones de la solución junto con ejemplos de código.

El primer paso en mi proceso fue averiguar cómo iba a obtener una copia del correo electrónico enviado al destinatario original. Para obtener una copia del cuerpo del correo electrónico, necesitas:


Opciones de Captura de Cuerpo de Correo Electrónico

Método

Quién crea la copia

Refleja cambios de seguimiento

Amigable para automatización

Usado en esta solución

Capturar antes de enviar

Aplicación

❌ No

✅ Sí

El servidor de correo almacena copia

Servidor de correo

✅ Sí

❌ Limitada

Función de Archivo de SparkPost

SparkPost

✅ Sí

✅ Sí


  1. Capturar el cuerpo del correo electrónico antes de enviar el correo

  2. Hacer que el servidor de correo almacene una copia

  3. Permitir que el servidor de correo cree una copia para almacenar

Si el servidor de correo está agregando elementos como el seguimiento de enlaces o apertura, no puedes usar #1 porque no reflejará los cambios de seguimiento de apertura/clics.

Eso significa que ya sea el servidor debe almacenar el correo electrónico o de alguna manera ofrecer una copia de ese correo para que lo almacenes. Dado que SparkPost no tiene un mecanismo de almacenamiento para cuerpos de correos electrónicos pero sí tiene una forma de crear una copia del correo, haremos que SparkPost nos envíe un duplicado del correo para almacenarlo en S3.

Esto se hace usando la función de Archivo de SparkPost. La función de Archivo de SparkPost le da al remitente la capacidad de decirle a SparkPost que envíe un duplicado del correo electrónico a una o más direcciones de correo y usar los mismos enlaces de seguimiento y apertura que el original. La documentación de SparkPost define su función de Archivo de la siguiente manera:

Los destinatarios en la lista de archivos recibirán una réplica exacta del mensaje que se envió a la dirección RCPT TO. En particular, los enlaces codificados destinados para el destinatario RCPT TO serán idénticos en los mensajes de archivo

Las únicas diferencias del correo RCPT TO son que algunos de los encabezados serán diferentes ya que la dirección de destino para el correo de archivo es diferente, ¡pero el cuerpo del correo será una réplica exacta!

Si deseas una explicación más profunda aquí hay un enlace a la documentación de SparkPost sobre la creación de copias duplicadas (o de archivo) de un correo electrónico.

Como nota al margen, SparkPost realmente te permite enviar correos electrónicos a direcciones de cc, cco y archivo. Para esta solución, estamos enfocados en las direcciones de archivo.

* Aviso * Los correos electrónicos archivados SOLO se pueden crear cuando se inyectan correos electrónicos en SparkPost a través de SMTP!

Ahora que sabemos cómo obtener una copia del correo original, necesitamos observar los datos de registro que se producen y algunas de las sutilezas dentro de esos datos. SparkPost rastrea todo lo que ocurre en sus servidores y ofrece esa información a ti en forma de eventos de mensajes. Esos eventos se almacenan en SparkPost por 10 días y se pueden extraer del servidor a través de una API RESTful llamada eventos de mensajes, o puedes hacer que SparkPost envíe esos eventos a cualquier número de aplicaciones de recolección que desees. El mecanismo de envío se realiza a través de webhooks y se hace en tiempo real.

Actualmente, hay 14 eventos diferentes que pueden sucederle a un correo electrónico.  Aquí hay una lista de los eventos actuales:

  • Bounce

  • ClickDelay

  • Delivery

  • Generation Failure

  • Generation Rejection

  • Initial Open

  • InjectionLink Unsubscribe

  • List Unsubscribe

  • Open

  • Out of Band

  • Policy RejectionSpam Complaint


* Sigue este enlace para una guía de referencia actualizada para una descripción de cada evento junto con los datos que se comparten para cada evento.

Cada evento tiene numerosos campos que coinciden con el tipo de evento.  Algunos campos como el transmission_id se encuentran en cada evento, pero otros campos pueden ser más específicos del evento; por ejemplo, solo los eventos de apertura y clic tienen información de geolocalización.


Identificadores Usados en el Sistema de Archivado

Identificador

De dónde se origina

Compartido entre

Propósito

Limitación

transmission_id

SparkPost outbound

Original, archivo, cc, cco

Correlaciona todos los eventos de mensajes

No disponible en retransmisión entrante

message_id

SparkPost outbound

Original + archivo

Identifica mensajes individuales

Diferente para cc/cco

UID Oculto

Inyectado por remitente

Salida + entrada

Vincula cuerpo de email archivado a eventos

Debe ser implementado de forma personalizada


Un registro de evento de mensaje muy importante para este proyecto es el transmission_id. Todos los registros de eventos de mensajes para el correo electrónico original, correo archivado y cualquier dirección de cc y cco compartirán el mismo transmission_id.

También hay una entrada común llamada message_id que tendrá el mismo id para cada registro del correo electrónico original y el correo electrónico archivado. Cualquier dirección de cc o cco tendrá su propio id para la entrada message_id .

Hasta ahora esto suena genial y sinceramente bastante fácil, pero ahora es la parte desafiante. Recuerda, para obtener el correo archivado, hacemos que SparkPost envíe un duplicado del correo original a otra dirección de correo que corresponda a alguna bandeja de entrada a la que tengas acceso. Pero para automatizar esta solución y almacenar el cuerpo del correo electrónico, voy a usar otra función de SparkPost llamada Redirección de Correo Electrónico Entrante. Lo que hace, es tomar todos los correos enviados a un dominio específico y procesarlos. Al procesarlos, descompone el correo y crea una estructura JSON que luego se entrega a una aplicación a través de un webhook. Ver Apéndice A para un ejemplo de JSON.

Si prestas mucha atención, notarás que la estructura JSON del relay entrante está perdiendo un campo muy importante; el transmission_id. Mientras que todos los correos electrónicos salientes tienen el transmission_id  con la misma entrada que vincula todos los datos del correo original, archivo, cc, y direcciones cco; SparkPost no tiene forma de saber que el correo capturado por el proceso entrante está conectado a cualquiera de los correos electrónicos salientes. El proceso entrante simplemente sabe que un correo fue enviado a un dominio específico y debe analizar el correo. Eso es todo. Tratará cualquier correo enviado a ese dominio de la misma manera, ya sea una respuesta de un cliente o el correo de archivo enviado desde SparkPost.

Entonces el truco es; ¿cómo pegas los datos salientes al proceso entrante que acaba de capturar la versión archivada del correo electrónico? Lo que decidí hacer es ocultar un id único en el cuerpo del correo electrónico. Cómo se haga esto depende de ti, pero simplemente creé un campo de entrada con la etiqueta oculta activada.

<input name="ArchiveCode" type="hidden" value="<<UID>>">

También agregué ese campo en el bloque de metadatos del encabezado X-MSYS-API que se pasa a SparkPost durante inyección. Este UID oculto será el pegamento para todo el proceso, y es un componente principal del proyecto y será discutido en profundidad en los siguientes posts del blog.

Ahora que tenemos el UID que unirá este proyecto y entendemos por qué es necesario, puedo comenzar a construir la visión del proyecto general y los posts del blog correspondientes.

  1. Captura y almacenamiento del correo de archivo junto con una entrada en la base de datos para búsqueda/indexación

  2. Capturar todos los datos de eventos de mensajes

  3. Crear una aplicación para ver el correo electrónico y todos los datos correspondientes

Aquí hay un diagrama simple del proyecto:

build an email archiving system - diagram


La primera entrega de código cubrirá el proceso de archivo y el almacenamiento del correo en S3, mientras que la segunda entrega de código cubrirá el almacenamiento de todos los datos de registro de eventos de mensajes en MySQL. Puedes esperar las dos primeras entregas de código y entradas del blog a principios de 2019.  Si tienes alguna pregunta o sugerencia, por favor no dudes en pasarlas.

Feliz Envío.
– Jeff


Apéndice A:

JSON file example - email archiving system

Otras noticias

Leer más de esta categoría

A person is standing at a desk while typing on a laptop.

La plataforma completa AI-native que escala con tu negocio.

© 2025 Bird

A person is standing at a desk while typing on a laptop.

La plataforma completa AI-native que escala con tu negocio.

© 2025 Bird