Construire un système d'archivage d'emails : Stocker le corps de l'email

Oiseau

4 mars 2019

Email

1 min read

Construire un système d'archivage d'emails : Stocker le corps de l'email

Oiseau

4 mars 2019

Email

1 min read

Construire un système d'archivage d'emails : Stocker le corps de l'email

Dans ce blog, je vais décrire le processus que j'ai suivi pour stocker le corps de l'e-mail sur S3 (Amazon Simple Storage Service) et les données auxiliaires dans une table MySQL pour un référencement croisé facile.

Dans ce blog, je vais décrire le processus que j'ai suivi pour stocker le corps de l'email sur S3 (Simple Store Service d'Amazon) et les données auxiliaires dans une table MySQL pour un croisement facile. En fin de compte, c'est le point de départ pour la base de code qui inclura une application permettant la recherche facile d'emails archivés, puis l'affichage de ces emails avec les données d'événements (journal). Le code de ce projet peut être trouvé dans le référentiel GitHub suivant : https://github.com/jeff-goldstein/PHPArchivePlatform.




Bien que je vais exploiter S3 et MySQL dans ce projet, ce ne sont en aucun cas les seules technologies qui peuvent être utilisées pour construire une plateforme d'archivage, mais étant donné leur omniprésence, je pensais qu'elles étaient un bon choix pour ce projet. Dans un système à grande échelle et à haut volume, j'utiliserais une base de données plus performante que MySQL, mais pour ce projet d'échantillon, MySQL est parfait.




J'ai détaillé ci-dessous les étapes que j'ai suivies dans cette première phase du projet :

  1. Créer l'email dupliqué pour archivage

  2. Utiliser les fonctionnalités d'archivage et de relais entrant de SparkPost pour envoyer une copie de l'email original de retour à SparkPost pour traitement en une structure JSON, puis envoyé à un collecteur de webhook (application)

  3. Démanteler la structure JSON pour obtenir les composants nécessaires

  4. Envoyer le corps de l'email à S3 pour stockage

  5. Enregistrer une entrée dans MySQL pour chaque email pour un croisement facile

Créer un Duplicate de l'Email

Dans SparkPost, la meilleure façon d'archiver un email est de créer une copie identique de l'email spécialement conçue pour les besoins d'archivage. Cela se fait en utilisant la fonctionnalité d'Archive de SparkPost. La fonctionnalité d'Archive de SparkPost donne à l'expéditeur la possibilité d'envoyer un double de l'email à une ou plusieurs adresses email.  Ce double utilise le même suivi et les mêmes liens d'ouverture que l'original. La documentation de SparkPost définit la fonctionnalité d'Archive de la manière suivante :

Les destinataires dans la liste d'archives recevront une réplique exacte du message envoyé à l'adresse RCPT TO. En particulier, tous les liens encodés destinés au destinataire RCPT TO seront identiques dans les messages d'archives.

La seule différence entre cette copie d'archive et le courriel original RCPT TO est que certains des en-têtes seront différents puisque l'adresse cible pour l'email d'archivage est différente, mais le corps de l'email sera une réplique exacte !

Si vous souhaitez une explication plus approfondie, voici un lien vers la documentation SparkPost sur la création de copies dupliquées (ou archivées) d'un email. Des exemples d'en-têtes X-MSYS-API pour ce projet sont montrés plus tard dans ce blog.

Il y a une mise en garde à cette approche ; bien que toutes les informations d'événement dans l'email original soient liées à la fois par un transmission_id et un message_id, il n'y a aucune information dans l'événement de relais entrant (le mécanisme pour obtenir et diffuser l'email d'archive) pour l'email dupliqué qui renvoie à l'un de ces deux identifiants et donc les informations pour l'email original. Cela signifie que nous devons placer des données dans le corps de l'email et l'en-tête de l'email original comme moyen de rassembler toutes les données de SparkPost de l'email original et de l'email d'archive.

Pour créer le code qui est placé dans le corps de l'email, j'ai utilisé le processus suivant dans l'application de création d'email.

  1. Quelque part dans le corps de l'email, j'ai placé l'entrée suivante :<input name="ArchiveCode" type="hidden" value="<<UID>>">

  2. Ensuite, j'ai créé un code unique et remplacé le champ <<UID>> :$uid = md5(uniqid(rand(), true)); $emailBody = str_replace(“<<UID>>,$uid,$emailBody);

    Voici un exemple de sortie :

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

  3. Ensuite, j'ai vérifié que j'ai ajouté le $UID au bloc meta_data de l'en-tête X-MSYS-API. Cette étape garantit que l'UID est intégré dans chaque sortie d'événement pour l'email 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>" } }

Maintenant, nous avons un moyen de relier toutes les données de l'email original au corps de l'email d'archive.

Obtention de la version Archive

Pour obtenir une copie d'un e-mail à des fins d'archivage, vous devez suivre les étapes suivantes :

  1. Créez un sous-domaine vers lequel vous enverrez tous les e-mails d'archive (duplicata)

  2. Configurez les enregistrements DNS appropriés pour que tous les e-mails envoyés à ce sous-domaine soient dirigés vers SparkPost

  3. Créez un domaine entrant dans SparkPost

  4. Créez un webhook entrant dans SparkPost

  5. Créez une application (collecteur) pour recevoir le flux de données du webhook de SparkPost

Les deux liens suivants peuvent vous aider à vous guider tout au long de ce processus :

  1. Document technique de SparkPost : Enabling Inbound Email Relaying & Relay Webhooks

  2. Aussi, le blog que j'ai écrit l'année dernière, Archiving Emails: A How-To Guide for Tracking Sent Mail vous guidera à travers la création du relais entrant au sein de SparkPost

* Remarque : à partir d'octobre 2018, la fonctionnalité d'archivage fonctionne uniquement lors de l'envoi d'e-mails utilisant une connexion SMTP vers SparkPost, l'API RESTful ne prend pas en charge cette fonctionnalité.  Cela ne devrait probablement pas poser de problème car la plupart des e-mails nécessitant ce niveau de contrôle d'audit ont tendance à être des e-mails personnalisés qui sont entièrement construits par une application backend avant que la livraison de l'e-mail ne soit nécessaire.

Pour obtenir une copie d'un e-mail à des fins d'archivage, vous devez suivre les étapes suivantes :

  1. Créez un sous-domaine vers lequel vous enverrez tous les e-mails d'archive (duplicata)

  2. Configurez les enregistrements DNS appropriés pour que tous les e-mails envoyés à ce sous-domaine soient dirigés vers SparkPost

  3. Créez un domaine entrant dans SparkPost

  4. Créez un webhook entrant dans SparkPost

  5. Créez une application (collecteur) pour recevoir le flux de données du webhook de SparkPost

Les deux liens suivants peuvent vous aider à vous guider tout au long de ce processus :

  1. Document technique de SparkPost : Enabling Inbound Email Relaying & Relay Webhooks

  2. Aussi, le blog que j'ai écrit l'année dernière, Archiving Emails: A How-To Guide for Tracking Sent Mail vous guidera à travers la création du relais entrant au sein de SparkPost

* Remarque : à partir d'octobre 2018, la fonctionnalité d'archivage fonctionne uniquement lors de l'envoi d'e-mails utilisant une connexion SMTP vers SparkPost, l'API RESTful ne prend pas en charge cette fonctionnalité.  Cela ne devrait probablement pas poser de problème car la plupart des e-mails nécessitant ce niveau de contrôle d'audit ont tendance à être des e-mails personnalisés qui sont entièrement construits par une application backend avant que la livraison de l'e-mail ne soit nécessaire.

Pour obtenir une copie d'un e-mail à des fins d'archivage, vous devez suivre les étapes suivantes :

  1. Créez un sous-domaine vers lequel vous enverrez tous les e-mails d'archive (duplicata)

  2. Configurez les enregistrements DNS appropriés pour que tous les e-mails envoyés à ce sous-domaine soient dirigés vers SparkPost

  3. Créez un domaine entrant dans SparkPost

  4. Créez un webhook entrant dans SparkPost

  5. Créez une application (collecteur) pour recevoir le flux de données du webhook de SparkPost

Les deux liens suivants peuvent vous aider à vous guider tout au long de ce processus :

  1. Document technique de SparkPost : Enabling Inbound Email Relaying & Relay Webhooks

  2. Aussi, le blog que j'ai écrit l'année dernière, Archiving Emails: A How-To Guide for Tracking Sent Mail vous guidera à travers la création du relais entrant au sein de SparkPost

* Remarque : à partir d'octobre 2018, la fonctionnalité d'archivage fonctionne uniquement lors de l'envoi d'e-mails utilisant une connexion SMTP vers SparkPost, l'API RESTful ne prend pas en charge cette fonctionnalité.  Cela ne devrait probablement pas poser de problème car la plupart des e-mails nécessitant ce niveau de contrôle d'audit ont tendance à être des e-mails personnalisés qui sont entièrement construits par une application backend avant que la livraison de l'e-mail ne soit nécessaire.

Obtention du double email dans une structure JSON

Dans la première phase de ce projet, tout ce que je stocke est le format d'email rfc822 dans S3 et certains champs de description de haut niveau dans une table SQL pour la recherche.  Puisque SparkPost enverra les données de l'email dans une structure JSON à ma plateforme d'archivage via des flux de données webhook, j'ai construit une application (souvent appelée un collector) qui accepte le flux de données Relay_Webhook.

Chaque paquet du SparkPost Relay_Webhook contiendra l'information d'un email en double à la fois, donc décomposer la structure JSON en composants ciblés pour ce projet est assez simple.  Dans mon code PHP, obtenir l'email formaté rfc822 a été aussi simple que les quelques lignes de code suivantes :

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'];}

Certaines informations que je souhaite stocker dans ma table SQL se trouvent dans un tableau de champs d'en-tête.  J'ai donc écrit une petite fonction qui accepte le tableau d'en-têtes et parcourt le tableau afin d'obtenir les données que je souhaitais stocker :

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;        }    } }

Maintenant que j'ai les données, je suis prêt à stocker le corps dans S3.

Stockage de l'email en double dans S3

Je suis désolé de vous décevoir, mais je ne vais pas donner un tutoriel étape par étape sur la création d'un bucket S3 pour stocker les emails, ni décrire comment créer la clé d'accès nécessaire dont vous aurez besoin dans votre application pour télécharger du contenu dans votre bucket ; il existe de meilleurs tutoriels sur ce sujet que je ne pourrais jamais écrire.  Voici quelques articles qui pourraient vous aider :

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

Ce que je vais faire, c'est souligner certains des paramètres que j'ai choisis qui se rapportent à un projet comme celui-ci.

  1. Contrôle d'accès.  Vous devez non seulement définir la sécurité pour le bucket, mais vous devez également définir les autorisations pour les éléments eux-mêmes.  Dans mon projet, j'utilise une politique très ouverte de lecture publique car les données d'exemple ne sont pas personnelles et je voulais un accès facile aux données.  Vous voudrez probablement un ensemble d'ACL beaucoup plus strict. Voici un bon article sur les paramètres ACL : https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html

  2. Archivage de l'Archive. Dans S3, il existe quelque chose appelé Gestion du Cycle de Vie.  Cela vous permet de déplacer des données d'un type de classe de stockage S3 à un autre.  Les différentes classes de stockage représentent le niveau d'accès dont vous avez besoin aux données stockées avec des coûts plus bas associés au stockage que vous accédez le moins. Une bonne rédaction des différentes classes et de leur transition peut être trouvée dans un guide AWS appelé, Transitioning Objects. Dans mon cas, j'ai choisi de créer un cycle de vie qui déplaçait chaque objet de Standard à Glacier après un an. L'accès Glacier est beaucoup moins cher que l'archive S3 standard et me fera économiser sur les coûts de stockage.

Une fois que j'ai créé le bucket S3 et configuré mes paramètres, S3 est prêt pour que je télécharge l'email conforme à rfc822 que j'ai obtenu depuis le flux de données SparkPost Relay Webhook. Mais avant de télécharger le contenu de l'email rfc822 sur S3, je dois créer un nom de fichier unique que j'utiliserai pour stocker cet email.

Pour le nom de fichier unique, je vais rechercher dans le corps de l'email l'id caché que l'application d'envoi a placé dans l'email et utiliser cet id comme nom de fichier. Il existe des moyens plus élégants pour extraire le connectorId du corps html, mais pour la simplicité et la clarté, je vais utiliser le code suivant :

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

* nous supposons que $inputField contient la valeur "ArchiveCode" et a été trouvé dans mon fichier config.php.

Avec l'UID, nous pouvons ensuite créer le nom de fichier qui sera utilisé dans S3 :

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

Maintenant j'ai la possibilité d'ouvrir ma connexion à S3 et de télécharger le fichier. Si vous jetez un œil au fichier s3.php dans le dépôt GitHub, vous verrez qu'il faut très peu de code pour télécharger le fichier.

Mon dernier pas est de journaliser cette entrée dans la table MYSQL.

Storing the Meta Data dans MySQL

Nous avons récupéré toutes les données nécessaires lors d'une étape précédente, donc l'étape de stockage est facile.  Dans cette première phase, j'ai choisi de construire une table avec les champs suivants :

  • Une entrée de champ automatisée pour la date/heure

  • L'adresse email cible (RCPT_TO)

  • Le timestamp de l'en-tête DATE de l'email

  • L'en-tête SUBJECT

  • L'en-tête de l'adresse email FROM

  • Le répertoire utilisé dans le bucket S3

  • Le nom de fichier S3 pour l'email archivé

La fonction nommée MySQLLog dans le fichier d'application upload.php passe par les étapes nécessaires pour ouvrir le lien vers MySQL, injecter la nouvelle ligne, tester les résultats et fermer le lien. J'ajoute une autre étape par précaution qui est de consigner ces données dans un fichier texte. Devrais-je faire beaucoup plus de journalisation pour les erreurs ? Oui. Mais je veux garder ce code léger pour lui permettre de s'exécuter extrêmement rapidement. Parfois, ce code sera appelé des centaines de fois par minute et doit être aussi efficace que possible. Dans les mises à jour futures, j'ajouterai du code annexe qui traitera les échecs et enverra ces échecs par email à un administrateur pour suivi.

En conclusion

Donc, en quelques étapes assez simples, nous avons pu parcourir la première phase de la création d'un système d'archivage d'e-mails robuste qui stocke le duplicata de l'e-mail dans S3 et les données de référence croisée dans une table MySQL.  Cela nous servira de fondation pour le reste du projet qui sera abordé dans plusieurs articles futurs.

Dans les futures révisions de ce projet, je m'attends à :

  1. Stocker tous les événements de journal de l'e-mail original

  2. Envoyer les erreurs de stockage à un administrateur lorsqu'un échec de chargement ou de journalisation se produit

  3. Réduire la complexité du collecteur.

  4. Ajouter une interface utilisateur pour visualiser toutes les données

  5. Soutenir la capacité de renvoyer l'e-mail

En attendant, j'espère que ce projet a été intéressant et utile pour vous ; bon envoi.

Connectons-vous avec un expert Bird.
Découvrez toute la puissance du Bird en 30 minutes.

En soumettant, vous acceptez que Bird puisse vous contacter au sujet de nos produits et services.

Vous pouvez vous désabonner à tout moment. Consultez la Déclaration de confidentialité de Bird pour plus de détails sur le traitement des données.

Company

Newsletter

Restez à jour avec Bird grâce aux mises à jour hebdomadaires dans votre boîte de réception.

Connectons-vous avec un expert Bird.
Découvrez toute la puissance du Bird en 30 minutes.

En soumettant, vous acceptez que Bird puisse vous contacter au sujet de nos produits et services.

Vous pouvez vous désabonner à tout moment. Consultez la Déclaration de confidentialité de Bird pour plus de détails sur le traitement des données.

Company

Newsletter

Restez à jour avec Bird grâce aux mises à jour hebdomadaires dans votre boîte de réception.

Connectons-vous avec un expert Bird.
Découvrez toute la puissance du Bird en 30 minutes.

En soumettant, vous acceptez que Bird puisse vous contacter au sujet de nos produits et services.

Vous pouvez vous désabonner à tout moment. Consultez la Déclaration de confidentialité de Bird pour plus de détails sur le traitement des données.

R

Atteindre

G

Grow

M

Manage

A

Automate

Company

Newsletter

Restez à jour avec Bird grâce aux mises à jour hebdomadaires dans votre boîte de réception.