Costruire un sistema di archiviazione delle email: memorizzare il corpo dell'email

In questo blog, descriverò il processo che ho seguito per memorizzare il corpo dell'email su S3 (Amazon Simple Store Service) e dati accessori in una tabella MySQL per un facile riferimento incrociato.

Autore

Uccello

Categoria

Email

Costruire un sistema di archiviazione delle email: memorizzare il corpo dell'email

In questo blog, descriverò il processo che ho seguito per memorizzare il corpo dell'email su S3 (Amazon Simple Store Service) e dati accessori in una tabella MySQL per un facile riferimento incrociato.

Autore

Uccello

Categoria

Email

Costruire un sistema di archiviazione delle email: memorizzare il corpo dell'email

In questo blog, descriverò il processo che ho seguito per memorizzare il corpo dell'email su S3 (Amazon Simple Store Service) e dati accessori in una tabella MySQL per un facile riferimento incrociato.

Autore

Uccello

Categoria

Email

In questo blog, descriverò il processo che ho seguito per memorizzare il corpo dell'email su S3 (Amazon Simple Store Service) e i dati accessori in una tabella MySQL per una facile referenziazione incrociata. Alla fine, questo è il punto di partenza per il codice sorgente che includerà un'applicazione che consentirà la facile ricerca di email archiviate e la visualizzazione di tali email insieme ai dati degli eventi (log). Il codice per questo progetto può essere trovato nel seguente repository GitHub: https://github.com/jeff-goldstein/PHPArchivePlatform.


Pur sfruttando S3 e MySQL in questo progetto, non sono assolutamente le uniche tecnologie che possono essere utilizzate per costruire una piattaforma di archiviazione, ma data la loro ubiquità, ho pensato fossero una buona scelta per questo progetto. In un sistema ad alta capacità a pieno regime utilizzerei un database ad alte prestazioni rispetto a MySQL, ma per questo progetto di esempio, MySQL è perfetto.


Ho dettagliato di seguito i passaggi che ho seguito in questa prima fase del progetto:

  1. Creazione dell'email duplicata per l'archiviazione

  2. Utilizzare le funzionalità di Archiviazione e Inbound Relay di SparkPost per inviare una copia dell'email originale a SparkPost per l'elaborazione in una struttura JSON, quindi inviata a un collector webhook (applicazione)

  3. Smontare la struttura JSON per ottenere i componenti necessari

  4. Inviare il corpo dell'email a S3 per la memorizzazione

  5. Registrare un'entrata in MySQL per ogni email per referenziazione incrociata


Creazione di un duplicato dell'email

In SparkPost, il modo migliore per archiviare un'email è creare una copia identica dell'email specificamente progettata per scopi di archiviazione. Questo viene fatto utilizzando la funzione Archive di SparkPost. La funzione Archive di SparkPost consente al mittente di inviare un duplicato dell'email a uno o più indirizzi email.  Questo duplicato utilizza gli stessi link di tracciamento e apertura dell'originale. La documentazione di SparkPost definisce la funzione Archive nel seguente modo:

I destinatari nell'elenco di archiviazione riceveranno una replica esatta del messaggio inviato all'indirizzo RCPT TO. In particolare, eventuali link codificati destinati al destinatario RCPT TO saranno identici nei messaggi di archiviazione

L'unica differenza tra questa copia di archiviazione e l'email originale RCPT TO è che alcuni degli header saranno diversi poiché l'indirizzo target per l'email di archiviazione è diverso, ma il corpo dell'email sarà una replica esatta!

Se desideri una spiegazione più approfondita, qui c'è un link alla documentazione di SparkPost sulla creazione di copie duplicate (o di archiviazione) di un'email. Le intestazioni degli API X-MSYS per questo progetto sono mostrate più avanti in questo blog.

C'è una avvertenza a questo approccio; mentre tutte le informazioni degli eventi nell'email originale sono collegate tramite sia un transmission_id che un message_id, non ci sono informazioni nell'evento di inbound relay (il meccanismo per ottenere e diffondere l'email di archiviazione) per l'email duplicata che si colleghi a uno di quei due id e quindi le informazioni per l'email originale. Questo significa che dobbiamo collocare i dati nel corpo dell'email e nell'intestazione dell'email originale come modo per collegare tutti i dati di SparkPost dall'email originale e dall'email di archiviazione.

Per creare il codice che viene inserito nel corpo dell'email, ho utilizzato il seguente processo nell'applicazione di creazione delle email.

  1. In qualche punto del corpo dell'email, ho inserito la seguente voce di input:<input name="ArchiveCode" type="hidden" value="<<UID>>">

  2. Quindi ho creato un codice unico e ho sostituito il campo <<UID>>:$uid = md5(uniqid(rand(), true)); $emailBody = str_replace(“<<UID>>,$uid,$emailBody);

    Qui c'è un esempio di output:

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

  3. Successivamente, ho fatto in modo di aggiungere il $UID al blocco meta_data dell'intestazione X-MSYS-API. Questo passaggio assicura che il UID sia incorporato in ciascun output di evento dell'email originale:

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

Ora abbiamo un modo per collegare tutti i dati dall'email originale al corpo dell'email di archiviazione.


Ottenere la versione di archiviazione

Per ottenere una copia di un'email per archiviazione, è necessario seguire i seguenti passaggi:

  1. Creare un sottodominio a cui inviare tutte le email di archiviazione (duplicate)

  2. Impostare i record DNS appropriati per avere tutte le email inviate a quel sottodominio a SparkPost

  3. Creare un dominio di inbound in SparkPost

  4. Creare un webhook inbound in SparkPost

  5. Creare un'applicazione (collector) per ricevere il flusso di dati webhook di SparkPost

I seguenti due link possono essere utilizzati per aiutarti a guidarti attraverso questo processo:

  1. Documentazione tecnica di SparkPost: Abilitare il Relay Email Inbound & Relay Webhooks

  2. Inoltre, il blog che ho scritto l'anno scorso, Archiviazione delle Email: Guida Pratica per il Monitoraggio della Posta Inviata ti guiderà attraverso la creazione del relay inbound all'interno di SparkPost

* Nota: a partire da ottobre 2018, la funzione Archive funziona solo quando si inviano email tramite una connessione SMTP a SparkPost, l'API RESTful non supporta questa funzione.  Probabilmente non è un problema perché la maggior parte delle email che necessitano di questo livello di controllo di audit tendono a essere email personalizzate che sono completamente costruite da un'applicazione backend prima che la consegna dell'email sia necessaria.

Ottenere l'email duplicata in una struttura JSON

Nella prima fase di questo progetto, tutto ciò che sto memorizzando è il formato email rfc822 in S3 e alcuni campi descrittivi di alto livello in una tabella SQL per la ricerca.  Poiché SparkPost invierà i dati dell'email in una struttura JSON alla mia piattaforma di archiviazione tramite flussi di dati webhook, ho costruito un'applicazione (spesso chiamata un collector) che accetta il flusso di dati Relay_Webhook.

Ogni pacchetto dal Relay_Webhook di SparkPost conterrà le informazioni di una email duplicata alla volta, quindi scomporre la struttura JSON nei componenti mirati per questo progetto è piuttosto semplice.  Nel mio codice PHP, ottenere l'email formattata in rfc822 è stato semplice come le seguenti poche righe di codice:

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

Alcune delle informazioni che voglio memorizzare nella mia tabella SQL risiedono in un array di campi header.  Così ho scritto una piccola funzione che accettava l'array di header e lo scorreva per ottenere i dati che ero interessato a memorizzare:

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

Ora che ho i dati, sono pronto per memorizzare il corpo in S3.


Memorizzare l'email duplicata in S3

Mi dispiace deluderti, ma non darò un tutorial passo passo su come creare un bucket S3 per memorizzare l'email né descriverò come creare la chiave di accesso necessaria per la tua applicazione per caricare contenuti nel tuo bucket; ci sono tutorial migliori su questo argomento di quanti io potrei mai scrivere.  Ecco un paio di articoli che potrebbero aiutarti:

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

Ciò che farò è sottolineare alcune delle impostazioni che ho scelto e che riguardano un progetto come questo.

  1. Controllo Accessi.  Non solo devi impostare la sicurezza per il bucket, ma devi impostare i permessi per gli elementi stessi.  Nel mio progetto, utilizzo una politica molto aperta di public-read perché i dati di esempio non sono personali e desidero un facile accesso ai dati.  Probabilmente vorrai un insieme di politiche ACL molto più rigido. Ecco un bel articolo sulle impostazioni ACL:

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

  2. Archiviazione dell'Archiviazione. In S3 c'è qualcosa chiamato Lifecycle Management.  Questo ti consente di spostare i dati da un tipo di classe di archiviazione S3 a un altro.  Le diverse classi di archiviazione rappresentano la quantità di accesso necessaria ai dati memorizzati con costi inferiori associati con l'archiviazione a cui accedi di meno. Una buona descrizione delle diverse classi e del passaggio attraverso di esse può essere trovata in una guida AWS chiamata, Transizione degli Oggetti. Nel mio caso, ho scelto di creare un ciclo di vita che spostasse ciascun oggetto da Standard a Glacier dopo un anno. L'accesso a Glacier è molto più economico rispetto all'archiviazione standard S3 e mi farà risparmiare soldi sui costi di archiviazione.

Una volta che ho creato il bucket S3 e impostato le mie impostazioni, S3 è pronto per me a caricare l'email conforme a rfc822 che ho ottenuto dal flusso di dati del Webhook di Relay di SparkPost. Ma prima di caricare il payload dell'email rfc822 su S3, devo creare un nome file unico che utilizzerò per memorizzare quell'email.

Per il nome file unico, cercherò nel corpo dell'email l'id nascosto che l'applicazione mittente ha collocato nell'email e utilizzerò quell'id come nome del file. Ci sono modi più eleganti per estrarre il connectorId dal corpo HTML, ma per semplicità e chiarezza utilizzerò il seguente codice:

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

* presumiamo che $inputField contenga il valore "ArchiveCode" e sia stato trovato nel mio file di config.php.

Con il UID, possiamo quindi creare il nome file che verrà utilizzato in S3:

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

Ora posso aprire la mia connessione a S3 e caricare il file. Se guardi il file s3.php nel repository GitHub vedrai che ci vogliono pochissime righe di codice per caricare il file.

Il mio ultimo passo è registrare questa voce nella tabella MYSQL.


Memorizzare i Metadati in MySQL

Abbiamo raccolto tutti i dati necessari in un passaggio precedente, quindi il passaggio di memorizzazione è facile.  In questa prima fase ho scelto di costruire una tabella con i seguenti campi:

  • Un'entrata di campo automatizzata per data/ora

  • L'indirizzo email target (RCPT_TO)

  • Il timestamp dall'intestazione DATE dell'email

  • L'intestazione SUBJECT

  • L'intestazione dell'indirizzo email FROM

  • La directory utilizzata nel bucket S3

  • Il nome file S3 per l'email archiviata

La funzione chiamata, MySQLLog all'interno del file upload.php segue i passaggi necessari per aprire il link a MySQL, iniettare la nuova riga, testare i risultati e chiudere il link. Aggiungo un altro passaggio per sicurezza e questo è registrare questi dati in un file di testo. Dovrei fare molta più registrazione per gli errori? Sì. Ma voglio mantenere questo codice leggero per consentire un'esecuzione estremamente veloce. A volte questo codice verrà chiamato centinaia di volte al minuto e deve essere il più efficiente possibile. In aggiornamenti futuri, aggiungerò codice accessorio che elaborerà i fallimenti e invierà quelle segnalazioni a un admin per il monitoraggio.

Riassumendo

Quindi, in pochi passaggi relativamente semplici, siamo stati in grado di percorrere la prima fase della costruzione di un robusto sistema di archiviazione delle email che conserva il duplicato dell'email in S3 e i dati di referenziazione incrociata in una tabella MySQL.  Questo ci darà una base per il resto del progetto che verrà affrontato in diversi post futuri.

Nei futuri aggiornamenti di questo progetto mi aspetterei di:

  1. Memorizzare tutti gli eventi di log dell'email originale

  2. Inviare errori di archiviazione a un admin quando si verifica un fallimento nel caricamento o nella registrazione

  3. Minimizzare la complessità del collector.

  4. Aggiungere un'interfaccia utente per visualizzare tutti i dati

  5. Supportare la possibilità di reinviare l'email

Nel frattempo, spero che questo progetto sia stato interessante e utile per te; buon invio.

Pronto a vedere Bird in azione?

Schedule a demo now.

La piattaforma alimentata dall'IA per Marketing, Supporto e Finanza

Cliccando su "Richiedi una demo" accetti di Bird's

La piattaforma alimentata dall'IA per Marketing, Supporto e Finanza

Cliccando su "Richiedi una demo" accetti di Bird's

La piattaforma alimentata dall'IA per Marketing, Supporto e Finanza

Cliccando su "Richiedi una demo" accetti di Bird's