Een e-mailarchiveringssysteem bouwen: Het opslaan van de e-mail body

Een e-mailarchiveringssysteem bouwen: Het opslaan van de e-mail body

Building an E-mail Archiving System: Storing the E-mail Body

Mar 4, 2019

Gepubliceerd door

Gepubliceerd door

MessageBird

MessageBird

-

Categorie:

Categorie:

Email

Email

Ready to see Bird
in action?

Ready to see Bird
in action?

Een e-mailarchiveringssysteem bouwen: Het opslaan van de e-mail body

In this blog, I will describe the process I went through to store the body of the email onto S3 (Amazon’s Simple Store Service) and ancillary data into a MySQL table for easy cross-referencing. Ultimately, this is the starting point for the code base that will include an application that will allow for easy searching of archived emails, and then displaying those emails along with the event (log) data. De code for this project can be found in the following GitHub repository: https://github.com/jeff-goldstein/PHPArchivePlatform.


Hoewel ik in dit project gebruik zal maken van S3 en MySQL, zijn dit zeker niet de enige technologieën die kunnen worden gebruikt om een archiveringsplatform te bouwen, maar gezien hun alomtegenwoordigheid leken ze me een goede keuze voor dit project. In een grootschalig systeem met grote volumes zou ik een database met hogere prestaties gebruiken dan MySQL, maar voor dit voorbeeldproject is MySQL perfect.


I have detailed below, the steps I took in this eerste fase of the project:

  1. De dubbele e-mail voor archivering aanmaken

  2. Gebruik de functies Archivering en Inbound Relay van SparkPost om een kopie van de oorspronkelijke e-mail terug te sturen naar SparkPost voor verwerking in een JSON-structuur, die vervolgens naar een webhook-verzamelaar (applicatie) wordt gestuurd.

  3. De JSON-structuur ontmantelen om de nodige componenten te verkrijgen

  4. De inhoud van de e-mail naar S3 sturen voor opslag

  5. Log een item in MySQL voor elke e-mail voor kruisverwijzingen


Een duplicaat van de e-mail maken

In SparkPost the best way to archive an email is to create an identical copy of the email specifically designed for archival purposes. This is done by using SparkPost’s Archive feature. SparkPost’s Archive feature gives the sender the ability to send a duplicate of the email to one or more email address.  This duplicate uses the same tracking and open links as the original. De SparkPost documentation defines the Archive feature in the following way:

Ontvangers in de archieflijst zullen een exacte replica ontvangen van het bericht dat naar het RCPT TO-adres is verzonden. In het bijzonder zullen alle gecodeerde links bestemd voor de RCPT TO-ontvanger identiek zijn in de archiefberichten.

Het enige verschil tussen deze archiefkopie en de originele RCPT TO e-mail is dat sommige headers anders zullen zijn omdat het doeladres voor de archiveringsmail anders is, maar de body van de e-mail zal een exacte replica zijn!

If you want a deeper explanation, here is a link naar de SparkPost documentation on creating duplicate (or archive) copies of an email. Sample X-MSYS-API headers for this project are shown later in this blog.

Er is één voorbehoud bij deze aanpak; terwijl alle gebeurtenisinformatie in de oorspronkelijke e-mail wordt gekoppeld door zowel een transmissie_id als een bericht_id, is er geen informatie in de inkomende relay gebeurtenis (het mechanisme voor het verkrijgen en verspreiden van de archief e-mail) voor de dubbele e-mail die terugkoppelt naar een van die twee id's en dus de informatie voor de oorspronkelijke e-mail. Dit betekent dat we gegevens in de email body en de header van de originele email moeten plaatsen om alle SparkPost gegevens van de originele en archief email aan elkaar te koppelen.

Om de code te maken die in de e-mail body wordt geplaatst, gebruikte ik het volgende proces in de e-mail creatie applicatie.

  1. Somewhere in the email body, I placed the following input entry:<input name="ArchiveCode" type="hidden" value="<<UID>>">

  2. Then I created a unique code and replaced the <<UID>> field:$uid = md5(uniqid(rand(), true)); $emailBody = str_replace(“<<UID>>,$uid,$emailBody);

    Hier is een voorbeelduitvoer:

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

  3. Vervolgens heb ik de $UID toegevoegd aan het meta_data blok van de X-MSYS-API header. Deze stap zorgt ervoor dat de UID wordt opgenomen in elke gebeurtenisuitvoer van de oorspronkelijke e-mail:

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

Nu hebben we een manier om alle gegevens van de oorspronkelijke e-mail te koppelen aan de e-mail body van het archief.


De archiefversie verkrijgen

Om een kopie van een e-mail te verkrijgen voor archivering, moet u de volgende stappen nemen:

  1. Maak een subdomein aan waarnaar u alle archief (dubbele) e-mail(s) zult sturen

  2. Stel de juiste DNS records in om alle e-mails die naar dat subdomein worden gestuurd naar SparkPost te sturen

  3. Creëer een inkomend domein in SparkPost

  4. Maak een inkomende webhook aan in SparkPost

  5. Maak een applicatie (collector) om de SparkPost webhook datastroom te ontvangen

De volgende twee links kunnen worden gebruikt om u bij dit proces te helpen:

  1. SparkPost technical doc: Enabling Inbound Email Relaying & Relay Webhooks

  2. Also, the blog I wrote last year, E-mails archiveren: Een handleiding voor het volgen van verzonden e-mail will walk you through the creation of the inbound relay within SparkPost

* Note: as of Oct 2018, the Archive feature only works when sending emails using an SMTP connection to SparkPost, the RESTful API does not support this feature.  That probably isn’t an issue because most emails that need this level of audit control tend to be personalized emails that are fully built out by a backend application before email delivery is needed.

Verkrijgen van de dubbele e-mail in een JSON-structuur

In the first phase of this project, all I’m storing is the rfc822 email format in S3 and some high-level description fields into a SQL table for searching.  Since SparkPost will send the email data in a JSON structure to my archiving platform via webhook data streams, I built an application (often referred to as a collector) that accepts the Relay_Webhook data stream.

Each package from the SparkPost Relay_Webhook will contain the information of one duplicate email at a time, so breaking the JSON structure down into the targeted components for this project is rather straightforward.  In my PHP code, getting the rfc822 formatted email was as easy as the following few lines of code:

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

Some of the information that I want to store into my SQL table resides in an array of header fields.  So I wrote a small function that accepted the header array and looped through the array in order to obtain the data I was interested in storing:

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

Nu ik de gegevens heb, ben ik klaar om het lichaam op te slaan in S3.


De dubbele e-mail opslaan in S3

I’m sorry to disappoint you but I’m not going to give a step by step tutorial on creating an S3 bucket for storing the email nor am I going to describe how to create the necessary access key you will need in your application for uploading content to your bucket; there are better tutorials on this subject than I could ever write.  Here a couple of articles that may help:

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

Wat ik zal doen is wijzen op enkele van de door mij gekozen instellingen die betrekking hebben op een project als dit.

  1. Toegangscontrole.  You not only need to set the security for the bucket, but you need to set the permissions for the items themselves.  In my project, I use a very open policy of public-read because the sample data is not personal and I wanted easy access naar de data.  You will probably want a much stricter set of ACL policies. Here is a nice article on ACL settings:

https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html

  2. Het archiveren van het archief. In S3 there is something called Lifecycle Management.  This allows you to move data from one type of S3 storage class to another.  The different storage classes represent the amount of access you need to the stored data with lower costs associated with the storage you access the least. A good write up of the different classes and transitioning through them can be found in an AWS guide called, Overgangsobjecten. In my case, I chose to create a lifecycle that moved each object from Standard to Glacier after one year. Glacier access is much cheaper than the standard S3 archive and will save me money in storage costs.

Zodra ik de S3 bucket heb aangemaakt en mijn instellingen op hun plaats staan, is S3 klaar voor mij om de rfc822 compliant email die ik heb verkregen van de SparkPost Relay Webhook data stream te uploaden. Maar voordat ik de rfc822 e-mail payload upload naar S3 moet ik een unieke bestandsnaam creëren die ik zal gebruiken om die e-mail op te slaan.

Voor de unieke bestandsnaam zoek ik in de e-mail body naar de verborgen id die de verzendende applicatie in de e-mail heeft geplaatst en gebruik die id als de naam van het bestand. Er zijn elegantere manieren om de connectorId uit de html body te halen, maar voor de eenvoud en duidelijkheid gebruik ik de volgende code:

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

* we nemen aan dat $inputField de waarde "ArchiveCode" bevat en gevonden werd in mijn config.php bestand.

Met de UID kunnen we dan de bestandsnaam maken die in S3 zal worden gebruikt:

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

Nu kan ik mijn verbinding met S3 openen en het bestand uploaden. Als je het s3.php bestand in de GitHub repository bekijkt, zie je dat er heel weinig code nodig is om het bestand te uploaden.

Mijn laatste stap is om deze invoer te loggen in de MYSQL tabel.


Metagegevens opslaan in MySQL

We grabbed all of the data necessary in a previous step, so the step of storage is easy.  In this first phase I chose to build a table with the following fields:

  • Een geautomatiseerde veldinvoer voor datum/tijd

  • Het e-mailadres van het doel (RCPT_TO)

  • Het tijdstempel uit de e-mail DATE header

  • De kop SUBJECT

  • De koptekst van het VAN e-mailadres

  • De in de S3 emmer gebruikte directory

  • De S3 bestandsnaam voor de gearchiveerde e-mail

De functie MySQLLog in het upload.php bestand doorloopt de nodige stappen om de link naar MySQL te openen, de nieuwe rij te injecteren, de resultaten te testen en de link te sluiten. Voor de goede orde voeg ik nog een stap toe en dat is het loggen van deze gegevens in een tekstbestand. Moet ik veel meer loggen voor fouten? Ja. Maar ik wil deze code licht houden, zodat hij extreem snel werkt. Deze code wordt soms honderden keren per minuut aangeroepen en moet zo efficiënt mogelijk zijn. In toekomstige updates zal ik aanvullende code toevoegen die fouten verwerkt en deze fouten e-mailt naar een beheerder voor controle.

Inpakken

So in a few fairly easy steps, we were able to walk through the first phase of building a robust email archiving system that holds the email duplicate in S3 and cross-referencing data in a MySQL table.  This will give us a foundation for the rest of the project that will be tackled in several future posts.

Bij toekomstige herzieningen van dit project verwacht ik:

  1. Alle logboekgebeurtenissen van de oorspronkelijke e-mail opslaan

  2. Stuur opslagfouten naar een beheerder wanneer een upload of log niet lukt

  3. Minimaliseer de complexiteit van de collector.

  4. Een UI toevoegen om alle gegevens te bekijken

  5. Ondersteuning van de mogelijkheid om de e-mail opnieuw te verzenden

Intussen hoop ik dat dit project voor u interessant en nuttig is geweest; veel plezier met verzenden.

Your new standard in Marketing, Pay & Sales. It's Bird

The right message -> to the right person -> aan de right time.

Your new standard in Marketing, Pay & Sales. It's Bird

The right message -> to the right person -> aan de right time.