Aufbau eines E-Mail-Archivierungssystems: Speichern des E-Mail-Textes

Aufbau eines E-Mail-Archivierungssystems: Speichern des E-Mail-Textes

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

Mar 4, 2019

Herausgegeben von

Herausgegeben von

Bird

Bird

-

Kategorie:

Kategorie:

Email

Email

Ready to see Bird
in action?

Ready to see Bird
in action?

Aufbau eines E-Mail-Archivierungssystems: Speichern des E-Mail-Textes

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. Die code for this project can be found in the following GitHub repository: https://github.com/jeff-goldstein/PHPArchivePlatform.


Obwohl ich in diesem Projekt S3 und MySQL einsetzen werde, sind dies keineswegs die einzigen Technologien, die für den Aufbau einer Archivierungsplattform verwendet werden können, aber angesichts ihrer Allgegenwärtigkeit hielt ich sie für eine gute Wahl für dieses Projekt. In einem groß angelegten System mit hohem Datenvolumen würde ich eine leistungsfähigere Datenbank als MySQL verwenden, aber für dieses Beispielprojekt ist MySQL perfekt geeignet.


I have detailed below, the steps I took in this erste Phase of the project:

  1. Erstellen des E-Mail-Duplikats für die Archivierung

  2. Verwenden Sie die Archivierungs- und Inbound-Relay-Funktionen von SparkPost, um eine Kopie der ursprünglichen E-Mail zurück an SparkPost zu senden, damit diese in einer JSON-Struktur verarbeitet und dann an einen Webhook-Kollektor (Anwendung) gesendet werden kann.

  3. Zerlegen Sie die JSON-Struktur, um die erforderlichen Komponenten zu erhalten

  4. Senden Sie den Text der E-Mail zur Speicherung an S3

  5. Protokollierung eines Eintrags in MySQL für jede E-Mail zum Zwecke des Querverweises


Duplikat der E-Mail erstellen

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. Die SparkPost documentation defines the Archive feature in the following way:

Die Empfänger in der Archivliste erhalten eine exakte Kopie der Nachricht, die an die RCPT TO-Adresse gesendet wurde. Insbesondere werden alle kodierten Links, die für den RCPT TO-Empfänger bestimmt sind, in den Archivnachrichten identisch sein

Der einzige Unterschied zwischen dieser Archivkopie und der ursprünglichen RCPT TO-E-Mail besteht darin, dass einige Kopfzeilen anders lauten, da die Zieladresse für die Archivierungs-E-Mail eine andere ist, aber der Text der E-Mail ist eine exakte Kopie!

If you want a deeper explanation, here is a link zum 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.

Bei diesem Ansatz gibt es eine Einschränkung: Während alle Ereignisinformationen in der Original-E-Mail durch eine transmission_id und eine message_id miteinander verbunden sind, gibt es im Inbound-Relay-Ereignis (dem Mechanismus zum Abrufen und Verbreiten der Archiv-E-Mail) für die doppelte E-Mail keine Informationen, die zu einer dieser beiden IDs und damit zu den Informationen für die Original-E-Mail zurückführen. Das bedeutet, dass wir Daten in den E-Mail-Text und die Kopfzeile der ursprünglichen E-Mail einfügen müssen, um alle SparkPost-Daten aus der ursprünglichen und der Archiv-E-Mail zusammenzuführen.

Um den Code zu erstellen, der in den E-Mail-Text eingefügt wird, bin ich in der Anwendung zur Erstellung von E-Mails wie folgt vorgegangen.

  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 ist ein Beispiel für die Ausgabe:

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

  3. Als nächstes habe ich die $UID in den meta_data-Block des X-MSYS-API-Headers eingefügt. Dieser Schritt sorgt dafür, dass die UID in jede Ereignisausgabe für die ursprüngliche E-Mail eingebettet wird:

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

Jetzt haben wir eine Möglichkeit, alle Daten aus der ursprünglichen E-Mail mit dem E-Mail-Text des Archivs zu verknüpfen.


Beschaffung der Archivversion

Um eine Kopie einer E-Mail für die Archivierung zu erhalten, müssen Sie die folgenden Schritte ausführen:

  1. Erstellen Sie eine Subdomain, an die Sie alle Archiv-E-Mails (Duplikate) senden werden

  2. Legen Sie die entsprechenden DNS-Einträge fest, damit alle E-Mails an diese Subdomäne an SparkPost gesendet werden.

  3. Erstellen Sie eine Inbound-Domäne in SparkPost

  4. Erstellen Sie einen eingehenden Webhook in SparkPost

  5. Erstellen Sie eine Anwendung (Kollektor), die den SparkPost-Webhook-Datenstrom empfängt

Die folgenden beiden Links können Ihnen bei diesem Prozess behilflich sein:

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

  2. Also, the blog I wrote last year, E-Mails archivieren: Ein Leitfaden zum Nachverfolgen gesendeter E-Mails 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.

Abrufen der doppelten E-Mail in einer JSON-Struktur

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 Kollektor) that accepts the Relais_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;        }    } }

Da ich nun die Daten habe, kann ich den Body in S3 speichern.


Speichern der E-Mail-Duplikate 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/

Ich werde auf einige der von mir gewählten Einstellungen hinweisen, die für ein Projekt wie dieses relevant sind.

  1. Zugangskontrolle.  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 zum 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. Archivierung des Archivs. 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, Übergang von Objekten. 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.

Sobald ich den S3-Bucket erstellt und meine Einstellungen vorgenommen habe, kann ich die rfc822-konforme E-Mail, die ich aus dem SparkPost Relay Webhook-Datenstrom erhalten habe, in S3 hochladen. Vor dem Hochladen der rfc822-E-Mail-Nutzdaten in S3 muss ich jedoch einen eindeutigen Dateinamen erstellen, den ich zum Speichern der E-Mail verwenden werde.

Für den eindeutigen Dateinamen suche ich im E-Mail-Text nach der versteckten ID, die die sendende Anwendung in die E-Mail eingefügt hat, und verwende diese ID als Dateinamen. Es gibt elegantere Möglichkeiten, die connectorId aus dem HTML-Text zu ziehen, aber der Einfachheit und Klarheit halber werde ich den folgenden Code verwenden:

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

* Wir nehmen an, dass $inputField den Wert "ArchiveCode" enthält und in meiner config.php Datei gefunden wurde.

Mit der UID können wir dann den Dateinamen erstellen, der in S3 verwendet werden soll:

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

Jetzt kann ich meine Verbindung zu S3 öffnen und die Datei hochladen. Wenn Sie sich die Datei s3.php im GitHub-Repository ansehen, werden Sie feststellen, dass zum Hochladen der Datei nur sehr wenig Code erforderlich ist.

Der letzte Schritt besteht darin, diesen Eintrag in der MYSQL-Tabelle zu protokollieren.


Speicherung der Metadaten 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:

  • Ein automatischer Feldeintrag für Datum/Uhrzeit

  • Die Ziel-E-Mail-Adresse (RCPT_TO)

  • Der Zeitstempel aus der DATE-Kopfzeile der E-Mail

  • Die SUBJECT-Kopfzeile

  • Die Kopfzeile der FROM-E-Mail-Adresse

  • Das im S3-Bucket verwendete Verzeichnis

  • Der S3-Dateiname für die archivierte E-Mail

Die Funktion mit dem Namen MySQLLog in der Datei upload.php durchläuft die notwendigen Schritte, um die Verbindung zu MySQL zu öffnen, die neue Zeile einzugeben, die Ergebnisse zu testen und die Verbindung zu schließen. Zur Sicherheit füge ich noch einen weiteren Schritt hinzu, nämlich die Protokollierung dieser Daten in einer Textdatei. Sollte ich bei Fehlern noch mehr protokollieren? Ja. Aber ich möchte diesen Code so einfach wie möglich halten, damit er extrem schnell ausgeführt werden kann. Dieser Code wird manchmal Hunderte von Malen pro Minute aufgerufen und muss daher so effizient wie möglich sein. In zukünftigen Updates werde ich zusätzlichen Code hinzufügen, der Fehler verarbeitet und diese Fehler per E-Mail an einen Administrator zur Überwachung weiterleitet.

Einpacken

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.

Bei künftigen Überarbeitungen dieses Projekts würde ich dies erwarten:

  1. Alle Log-Ereignisse der ursprünglichen E-Mail speichern

  2. Senden von Speicherfehlern an einen Administrator, wenn ein Fehler beim Hochladen oder Protokollieren auftritt

  3. Minimieren Sie die Komplexität des Kollektors.

  4. Hinzufügen einer UI zur Anzeige aller Daten

  5. Unterstützung der Möglichkeit, die E-Mail erneut zu senden

In der Zwischenzeit hoffe ich, dass dieses Projekt für Sie interessant und hilfreich war; viel Spaß beim Senden.

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

The right message -> to the right person -> am right time.

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

The right message -> to the right person -> am right time.