Reach

Grow

Manage

Automate

Reach

Grow

Manage

Automate

Construyendo un sistema de archivo de correos electrónicos: Almacenando el cuerpo del correo electrónico

Pájaro

4 mar 2019

Correo electrónico

1 min read

Construyendo un sistema de archivo de correos electrónicos: Almacenando el cuerpo del correo electrónico

Pájaro

4 mar 2019

Correo electrónico

1 min read

Construyendo un sistema de archivo de correos electrónicos: Almacenando el cuerpo del correo electrónico

En este blog, describiré el proceso que seguí para almacenar el cuerpo del correo electrónico en S3 (el Servicio de Almacenamiento Simple de Amazon) y los datos auxiliares en una tabla MySQL para facilitar la referencia cruzada.

En este blog, describiré el proceso por el que pasé para almacenar el cuerpo del correo electrónico en S3 (Simple Store Service de Amazon) y datos auxiliares en una tabla MySQL para facilitar la referencia cruzada. En última instancia, este es el punto de partida para la base de código que incluirá una aplicación que permitirá una búsqueda fácil de correos electrónicos archivados, y luego mostrará esos correos electrónicos junto con los datos del evento (registro). El código para este proyecto se puede encontrar en el siguiente repositorio de GitHub: https://github.com/jeff-goldstein/PHPArchivePlatform.




Si bien aprovecharé S3 y MySQL en este proyecto, de ninguna manera son estas las únicas tecnologías que se pueden usar para construir una plataforma de archivo, pero dada su ubicuidad, pensé que eran una buena elección para este proyecto. En un sistema a gran escala de alto volumen, usaría una base de datos de mayor rendimiento que MySQL, pero para este proyecto de muestra, MySQL es perfecto.




He detallado a continuación, los pasos que seguí en esta primera fase del proyecto:

  1. Crear el correo electrónico duplicado para archivar

  2. Utilizar las características de Archiving y Inbound Relay de SparkPost para enviar una copia del correo electrónico original de vuelta a SparkPost para procesarlo en una estructura JSON, luego enviado a un colector de webhook (aplicación)

  3. Desmantelar la estructura JSON para obtener los componentes necesarios

  4. Enviar el cuerpo del correo electrónico a S3 para su almacenamiento

  5. Registrar una entrada en MySQL para cada correo electrónico para la referencia cruzada

Creando un Duplicate del Email

En SparkPost, la mejor manera de archivar un correo electrónico es crear una copia idéntica del correo específicamente diseñada para fines de archivo. Esto se hace utilizando la función de Archivo de SparkPost. La función de Archivo de SparkPost le da al remitente la capacidad de enviar un duplicado del correo electrónico a una o más direcciones de correo.  Este duplicado utiliza los mismos enlaces de seguimiento y apertura que el original. La documentación de SparkPost define la función de Archivo de la siguiente manera:

Los destinatarios en la lista de archivo recibirán una réplica exacta del mensaje que se envió a la dirección RCPT TO. En particular, cualquier enlace codificado destinado al destinatario RCPT TO será idéntico en los mensajes archivados.

La única diferencia entre esta copia del archivo y el correo RCPT TO original es que algunos de los encabezados serán diferentes ya que la dirección de destino para el correo electrónico de archivo es diferente, ¡pero el cuerpo del correo electrónico será una réplica exacta!

Si desea una explicación más profunda, aquí hay un enlace a la documentación de SparkPost sobre cómo crear copias duplicadas (o de archivo) de un correo electrónico. Se muestran ejemplos de encabezados X-MSYS-API para este proyecto más adelante en este blog.

Hay una advertencia a este enfoque; aunque toda la información del evento en el correo original está vinculada tanto por un transmission_id como por un message_id, no hay información en el evento de retransmisión entrante (el mecanismo para obtener y difundir el correo de archivo) para el correo electrónico duplicado que se vincule a uno de esos dos id's y, por lo tanto, a la información del correo original. Esto significa que necesitamos colocar datos en el cuerpo del correo electrónico y el encabezado del correo original como una forma de vincular toda la información de SparkPost del correo original y el de archivo.

Para crear el código que se inserta en el cuerpo del correo electrónico, utilicé el siguiente proceso en la aplicación de creación de correos electrónicos.

  1. En alguna parte del cuerpo del correo, coloqué la siguiente entrada de formulario:<input name="ArchiveCode" type="hidden" value="<<UID>>">

  2. Luego, creé un código único y reemplacé el campo <<UID>>: $uid = md5(uniqid(rand(), true)); $emailBody = str_replace(“<<UID>>,$uid,$emailBody);

    Aquí hay un ejemplo de salida:

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

  3. Después, me aseguré de agregar el $UID al bloque meta_data del encabezado X-MSYS-API. Este paso asegura que el UID se incruste en cada salida de evento para el correo original:

X-MSYS-API:{ "campaign_id":"<my_campaign>", "metadata":{ "UID":"<UID>" }, "archive":[ { "email":"archive@geekwithapersonality.com" } ], "options":{ "open_tracking":false, "click_tracking":false, "transactional":false, "ip_pool":"<my_ip_pool>" } }

Ahora tenemos una forma de vincular todos los datos del correo original al cuerpo del correo de archivo.

Obteniendo la versión Archive

Para obtener una copia de un correo electrónico para archivo, debes seguir los siguientes pasos:

  1. Crea un subdominio al que enviarás todos los correos electrónicos de archivo (duplicados)

  2. Configura los registros DNS apropiados para que todos los correos electrónicos enviados a ese subdominio se dirijan a SparkPost

  3. Crea un dominio entrante en SparkPost

  4. Crea un webhook entrante en SparkPost

  5. Crea una aplicación (collector) para recibir el flujo de datos del webhook de SparkPost

Los siguientes dos enlaces se pueden usar para guiarte en este proceso:

  1. Documento técnico de SparkPost: Enabling Inbound Email Relaying & Relay Webhooks

  2. Además, el blog que escribí el año pasado, Archiving Emails: A How-To Guide for Tracking Sent Mail, te guiará a través de la creación del relay entrante dentro de SparkPost

* Nota: a partir de octubre de 2018, la función de Archivo solo funciona al enviar correos electrónicos usando una conexión SMTP a SparkPost, la API RESTful no admite esta función.  Eso probablemente no sea un problema porque la mayoría de los correos electrónicos que requieren este nivel de control de auditoría tienden a ser correos electrónicos personalizados que son completamente construidos por una aplicación backend antes de que se necesite la entrega del correo electrónico.

Para obtener una copia de un correo electrónico para archivo, debes seguir los siguientes pasos:

  1. Crea un subdominio al que enviarás todos los correos electrónicos de archivo (duplicados)

  2. Configura los registros DNS apropiados para que todos los correos electrónicos enviados a ese subdominio se dirijan a SparkPost

  3. Crea un dominio entrante en SparkPost

  4. Crea un webhook entrante en SparkPost

  5. Crea una aplicación (collector) para recibir el flujo de datos del webhook de SparkPost

Los siguientes dos enlaces se pueden usar para guiarte en este proceso:

  1. Documento técnico de SparkPost: Enabling Inbound Email Relaying & Relay Webhooks

  2. Además, el blog que escribí el año pasado, Archiving Emails: A How-To Guide for Tracking Sent Mail, te guiará a través de la creación del relay entrante dentro de SparkPost

* Nota: a partir de octubre de 2018, la función de Archivo solo funciona al enviar correos electrónicos usando una conexión SMTP a SparkPost, la API RESTful no admite esta función.  Eso probablemente no sea un problema porque la mayoría de los correos electrónicos que requieren este nivel de control de auditoría tienden a ser correos electrónicos personalizados que son completamente construidos por una aplicación backend antes de que se necesite la entrega del correo electrónico.

Para obtener una copia de un correo electrónico para archivo, debes seguir los siguientes pasos:

  1. Crea un subdominio al que enviarás todos los correos electrónicos de archivo (duplicados)

  2. Configura los registros DNS apropiados para que todos los correos electrónicos enviados a ese subdominio se dirijan a SparkPost

  3. Crea un dominio entrante en SparkPost

  4. Crea un webhook entrante en SparkPost

  5. Crea una aplicación (collector) para recibir el flujo de datos del webhook de SparkPost

Los siguientes dos enlaces se pueden usar para guiarte en este proceso:

  1. Documento técnico de SparkPost: Enabling Inbound Email Relaying & Relay Webhooks

  2. Además, el blog que escribí el año pasado, Archiving Emails: A How-To Guide for Tracking Sent Mail, te guiará a través de la creación del relay entrante dentro de SparkPost

* Nota: a partir de octubre de 2018, la función de Archivo solo funciona al enviar correos electrónicos usando una conexión SMTP a SparkPost, la API RESTful no admite esta función.  Eso probablemente no sea un problema porque la mayoría de los correos electrónicos que requieren este nivel de control de auditoría tienden a ser correos electrónicos personalizados que son completamente construidos por una aplicación backend antes de que se necesite la entrega del correo electrónico.

Obteniendo el email duplicado en una estructura JSON

En la primera fase de este proyecto, todo lo que estoy almacenando es el formato de correo electrónico rfc822 en S3 y algunos campos de descripción de alto nivel en una tabla SQL para búsqueda.  Dado que SparkPost enviará los datos del correo electrónico en una estructura JSON a mi plataforma de archivo a través de flujos de datos webhook, construí una aplicación (a menudo referida como un collector) que acepta el flujo de datos Relay_Webhook.

Cada paquete del SparkPost Relay_Webhook contendrá la información de un correo electrónico duplicado a la vez, por lo que desglosar la estructura JSON en los componentes específicos para este proyecto es bastante sencillo.  En mi código PHP, obtener el correo electrónico con formato rfc822 fue tan fácil como las siguientes pocas líneas de código:

if ($verb == "POST") { $body = file_get_contents("php://input"); $fields = json_decode($body, true); $rfc822body = $fields['0']['msys']['relay_message']['content']['email_rfc822']; $htmlbody = $fields['0']['msys']['relay_message']['content'][html'] $headers = $fields['0']['msys']['relay_message']['content']['headers'];}

Parte de la información que quiero almacenar en mi tabla SQL reside en un array de campos de encabezado.  Así que escribí una pequeña función que aceptó el array de encabezado y recorrió el array para obtener los datos que me interesaba almacenar:

function get_important_headers($headers, &$original_to, &$headerDate, &$subject, &$from) {    foreach ($headers as $key => $value) {        foreach ($value as $key_sub => $value_sub) {            if ($key_sub == 'To') $original_to = $value_sub;            if ($key_sub == 'Date') $headerDate = $value_sub;            if ($key_sub == 'Subject') $subject = $value_sub;            if ($key_sub == 'From') $from = $value_sub;        }    } }

Ahora que tengo los datos, estoy listo para almacenar el cuerpo en S3.

Almacenar el correo electrónico duplicado en S3

Lo siento por decepcionarte, pero no voy a dar un tutorial paso a paso sobre cómo crear un bucket S3 para almacenar el correo electrónico, ni voy a describir cómo crear la clave de acceso necesaria que necesitarás en tu aplicación para subir contenido a tu bucket; hay mejores tutoriales sobre este tema que los que podría escribir.  Aquí tienes un par de artículos que pueden ayudar:

https://docs.aws.amazon.com/quickstarts/latest/s3backup/step-1-create-bucket.html
https://aws.amazon.com/blogs/security/wheres-my-secret-access-key/

Lo que haré es señalar algunos de los ajustes que elegí que se relacionan con un proyecto como este.

  1. Control de Acceso.  No solo necesitas establecer la seguridad para el bucket, sino que necesitas establecer los permisos para los propios elementos.  En mi proyecto, utilizo una política muy abierta de lectura pública porque los datos de ejemplo no son personales y quería un acceso fácil a los datos.  Probablemente querrás un conjunto de políticas ACL mucho más estricto. Aquí hay un buen artículo sobre configuraciones de ACL: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html

  2. Archivando el Archivo. En S3 hay algo llamado Gestión del Ciclo de Vida.  Esto te permite mover datos de un tipo de clase de almacenamiento S3 a otro.  Las diferentes clases de almacenamiento representan la cantidad de acceso que necesitas a los datos almacenados con costos más bajos asociados con el almacenamiento al que accedes menos. Una buena explicación de las diferentes clases y su transición se puede encontrar en una guía de AWS llamada, Transitioning Objects. En mi caso, elegí crear un ciclo de vida que moviera cada objeto de Standard a Glacier después de un año. El acceso a Glacier es mucho más barato que el archivo estándar de S3 y me ahorrará dinero en costos de almacenamiento.

Una vez que tengo el bucket S3 creado y mis ajustes en su lugar, S3 está listo para que suba el correo electrónico compatible con rfc822 que obtuve del flujo de datos de SparkPost Relay Webhook. Pero antes de subir la carga de correo electrónico rfc822 a S3 necesito crear un nombre de archivo único que usaré para almacenar ese correo electrónico.

Para el nombre de archivo único, voy a buscar en el cuerpo del correo electrónico la id oculta que la aplicación remitente insertó en el correo electrónico y usaré esa id como el nombre del archivo. Hay maneras más elegantes de extraer el connectorId del cuerpo html, pero por simplicidad y claridad voy a usar el siguiente código:

       $start = strpos($htmlbody, $inputField);          $start = strpos($htmlbody, "value=", $start) + 7;        $end = strpos($htmlbody, ">", $start) - 1;        $length = $end - $start;        $UID = substr($html, $start, $length);

* asumimos que $inputField contiene el valor “ArchiveCode” y fue encontrado en mi archivo config.php.

Con el UID, luego podemos crear el nombre de archivo que se usará en S3:

$fileName = $ArchiveDirectory . '/' . $UID . '.eml';

Ahora puedo abrir mi conexión a S3 y subir el archivo. Si miras el archivo s3.php en el repositorio de GitHub verás que se requiere muy poco código para subir el archivo.

Mi último paso es registrar esta entrada en la tabla MYSQL.

Almacenando los Meta Data en MySQL

Recopilamos todos los datos necesarios en un paso anterior, por lo que el paso de almacenamiento es fácil.  En esta primera fase, elegí construir una tabla con los siguientes campos:

  • Una entrada de campo automatizada para fecha/hora

  • La dirección de correo electrónico de destino (RCPT_TO)

  • La marca de tiempo del encabezado de la fecha del correo electrónico

  • El encabezado SUBJECT

  • El encabezado de la dirección de correo electrónico FROM

  • El directorio utilizado en el bucket S3

  • El nombre de archivo S3 para el correo electrónico archivado

La función llamada MySQLLog dentro del archivo de aplicación upload.php atraviesa los pasos necesarios para abrir el enlace a MySQL, inyectar la nueva fila, probar los resultados y cerrar el enlace. Agrego otro paso por si acaso, que es registrar estos datos en un archivo de texto. ¿Debería hacer mucho más registro para errores? Sí. Pero quiero mantener este código ligero para permitirle ejecutar extremadamente rápido. A veces este código se llamará cientos de veces por minuto y necesita ser lo más eficiente posible. En futuras actualizaciones, agregaré código auxiliar que procesará las fallas y enviará esos errores por correo electrónico a un administrador para su monitoreo.

En resumen

Así que, en unos pocos pasos bastante sencillos, pudimos recorrer la primera fase de construcción de un sistema robusto de archivo de correos electrónicos que guarda el duplicado del correo en S3 y referencia cruzada de datos en una tabla MySQL.  Esto nos dará una base para el resto del proyecto que se abordará en varios futuros posts.

En futuras revisiones de este proyecto, esperaría:

  1. Almacenar todos los eventos de registro del correo original

  2. Enviar errores de almacenamiento a un administrador cuando ocurra una falla en la carga o registro

  3. Minimizar la complejidad del colector.

  4. Agregar una interfaz de usuario para ver todos los datos

  5. Soportar la capacidad de reenviar el correo

Mientras tanto, espero que este proyecto haya sido interesante y útil para usted; feliz envío.

Conectémosle con un experto de Bird.
Vea el poder completo del Bird en 30 minutos.

Al enviar, aceptas que Bird pueda contactarte sobre nuestros productos y servicios.

Puedes darte de baja en cualquier momento. Consulta el Aviso de Privacidad de Bird para obtener detalles sobre el procesamiento de datos.

Company

Newsletter

Mantente al día con Bird a través de actualizaciones semanales en tu buzón.

Conectémosle con un experto de Bird.
Vea el poder completo del Bird en 30 minutos.

Al enviar, aceptas que Bird pueda contactarte sobre nuestros productos y servicios.

Puedes darte de baja en cualquier momento. Consulta el Aviso de Privacidad de Bird para obtener detalles sobre el procesamiento de datos.

Company

Newsletter

Mantente al día con Bird a través de actualizaciones semanales en tu buzón.

Conectémosle con un experto de Bird.
Vea el poder completo del Bird en 30 minutos.

Al enviar, aceptas que Bird pueda contactarte sobre nuestros productos y servicios.

Puedes darte de baja en cualquier momento. Consulta el Aviso de Privacidad de Bird para obtener detalles sobre el procesamiento de datos.

R

Reach

G

Grow

M

Manage

A

Automate

Company

Newsletter

Mantente al día con Bird a través de actualizaciones semanales en tu buzón.