
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'e-mail sur S3 (Service de Stockage Simple d'Amazon) et les données auxiliaires dans une table MySQL pour un référencement croisé facile. En fin de compte, c'est le point de départ pour la base de code qui inclura une application permettant une recherche facile des e-mails archivés, puis l'affichage de ces e-mails avec les données d'événements (journal). Le code de ce projet peut être trouvé dans le repository GitHub suivant : https://github.com/jeff-goldstein/PHPArchivePlatform.
Bien que je vais utiliser S3 et MySQL dans ce projet, ces technologies ne sont en aucun cas les seules 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'exemple, MySQL est parfait. Pour les organisations envisageant PostgreSQL comme choix de base de données d'archivage, la mise en œuvre de procédures de sauvegarde et de restauration adéquates est essentielle pour maintenir l'intégrité des données dans les systèmes de production.
J'ai détaillé ci-dessous les étapes que j'ai prises dans cette première phase du projet :
Création de l'e-mail en double pour l'archivage
Utiliser les fonctionnalités d'Archiving et Inbound Relay de SparkPost pour envoyer une copie de l'e-mail original à SparkPost pour traitement dans une structure JSON, puis envoyée à un collecteur de webhook (application)
Démanteler la structure JSON pour obtenir les composants nécessaires
Envoyer le corps de l'e-mail à S3 pour stockage
Enregistrer une entrée dans MySQL pour chaque e-mail pour le référencement croisé
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écifiquement conçue pour les fins d'archivage. Ceci est réalisé en utilisant la fonctionnalité Archive de SparkPost. La fonctionnalité Archive de SparkPost donne à l'expéditeur la possibilité d'envoyer un duplicata de l'email à une ou plusieurs adresses email. Ce duplicata utilise les mêmes liens de suivi et d'ouverture que l'original. La documentation de SparkPost définit la fonctionnalité Archive de la manière suivante :
Les destinataires dans la liste d'archive recevront une réplique exacte du message qui a été envoyé à l'adresse RCPT TO. En particulier, tout lien encodé destiné au destinataire RCPT TO sera identique dans les messages d'archive.
La seule différence entre cette copie d'archive et l'email 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 de SparkPost sur la création de copies d'email en double (ou d'archive). Des échantillons de X-MSYS-API headers pour ce projet sont présentés plus tard dans ce blog.
Il y a une réserve à 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 pas d'information dans l'événement de relais entrant (le mécanisme pour obtenir et diffuser l'email d'archive) pour l'email dupliqué qui se rapporte à l'un de ces deux identifiants et donc aux informations de 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 réunir toutes les données SparkPost de l'email original et de l'email d'archive.
Afin de 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.
Quelque part dans le corps de l'email, j'ai placé l'entrée suivante :<input name="ArchiveCode" type="hidden" value="<<UID>>">
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">
Ensuite, je me suis assuré d'ajouter le $UID au bloc meta_data de l'en-tête X-MSYS-API. Cette étape s'assure que le UID est intégré dans chaque sortie d'événement pour l'email original :
Désormais, nous avons un moyen de lier toutes les données de l'email original au corps de l'email d'archive.
Obtention de la version Archive
Obtention du double email dans une structure JSON
Dans la première phase de ce projet, tout ce que je stocke est le format de courrier électronique rfc822 dans S3 et quelques champs de description de haut niveau dans une table SQL pour la recherche. Étant donné que SparkPost enverra les données de courrier électronique 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 les informations d'un courrier électronique doublé à la fois, donc décomposer la structure JSON en composants ciblés pour ce projet est plutôt simple. Dans mon code PHP, obtenir le courriel formaté en rfc822 était aussi facile que les quelques lignes de code suivantes :
Certaines des informations que je veux stocker dans ma table SQL résident dans un tableau de champs d'en-tête. J'ai donc écrit une petite fonction qui accepte le tableau d'en-tête et parcourt le tableau afin d'obtenir les données que je souhaitais stocker :
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 vous donner un tutoriel pas à pas sur la création d'un bucket S3 pour stocker l’email, 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 sur 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 concernent un projet comme celui-ci.
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 souhaiterez probablement un ensemble de politiques ACL beaucoup plus strictes. Voici un bon article sur les paramètres ACL : https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html
Archivage de l’archive. Dans S3, il existe ce qu'on appelle la 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 la quantité d'accès dont vous avez besoin aux données stockées avec des coûts inférieurs associés au stockage que vous consultez le moins. Un bon exposé des différentes classes et de leur transition peut être trouvé dans un guide AWS appelé, Transitioning Objects. Dans mon cas, j'ai choisi de créer un cycle de vie qui déplace chaque objet de Standard à Glacier après un an. L'accès à Glacier est bien moins cher que l'archive standard S3 et me permettra d'économiser sur les coûts de stockage.
Une fois le bucket S3 créé et mes paramètres en place, S3 est prêt pour moi à télécharger l’email conforme à la RFC822 que j'ai obtenu à partir du flux de données SparkPost Relay Webhook. Mais avant de télécharger la charge utile de l’email RFC822 dans 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’identifiant caché que l'application d'envoi a placé dans l’email et utiliser cet identifiant comme nom du fichier. Il existe des moyens plus élégants pour extraire le connectorId du corps HTML, mais pour des raisons de simplicité et de clarté, je vais utiliser le code suivant :
* nous supposons que $inputField contient la valeur “ArchiveCode” et a été trouvé dans mon fichier config.php.
Avec l’UID, nous pouvons alors créer le nom de fichier qui sera utilisé dans S3 :
$fileName = $ArchiveDirectory . '/' . $UID . '.eml';
Je peux maintenant ouvrir ma connexion à S3 et télécharger le fichier. Si vous regardez le 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.
Ma dernière étape consiste à enregistrer 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 à :
Stocker tous les événements de journal de l'e-mail original
Envoyer les erreurs de stockage à un administrateur lorsqu'un échec de chargement ou de journalisation se produit
Réduire la complexité du collecteur.
Ajouter une interface utilisateur pour visualiser toutes les données
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.