Reach

Grow

Manage

Automate

Reach

Grow

Manage

Automate

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

Uccello

4 mar 2019

Email

1 min read

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

Uccello

4 mar 2019

Email

1 min read

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.

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

Sebbene userò 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 che fossero una buona scelta per questo progetto. In un sistema ad alta scala e alto volume utilizzerei un database con prestazioni migliori rispetto a MySQL, ma per questo progetto di esempio, MySQL è perfetto. Per le organizzazioni che considerano PostgreSQL come la loro scelta di database di archiviazione, implementare correttamente le procedure di backup e ripristino è essenziale per mantenere l'integrità dei dati nei sistemi di produzione.

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

  1. Creazione dell'email duplicata per l'archiviazione

  2. Usare le funzionalità di Archiving e Inbound Relay di SparkPost per inviare una copia dell'email originale nuovamente a SparkPost per l'elaborazione in una struttura JSON, quindi inviata a un raccoglitore 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 il riferimento incrociato

Creare un Duplicato dell'Email

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

I destinatari nella lista dell'archivio riceveranno una replica esatta del messaggio inviato all'indirizzo RCPT TO. In particolare, i link codificati destinati al destinatario RCPT TO saranno identici nei messaggi di archivio.

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

Se desideri una spiegazione più approfondita, ecco un link alla documentazione di SparkPost sulla creazione di copie duplicate (o di archivio) di un'email. Gli header campione X-MSYS-API per questo progetto sono mostrati più avanti in questo blog.

Esiste una avvertenza per questo approccio; mentre tutte le informazioni sugli eventi nell'email originale sono legate insieme sia da un transmission_id che da un message_id, non vi sono informazioni nell'evento di inbound relay (il meccanismo per ottenere e diffondere l'email di archivio) per l'email duplicata che si ricollega a uno di questi due id e quindi alle informazioni per l'email originale. Questo significa che dobbiamo inserire dati nel corpo dell'email e nell'header dell'email originale come un modo per collegare tutti i dati SparkPost dall'email originale e da quella di archivio.

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

  1. Da qualche parte nel corpo dell'email, ho inserito il seguente ingresso:<input name="ArchiveCode" type="hidden" value="<<UID>>">

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

    Ecco un esempio di output:

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

  3. Dopo ho verificato di aver aggiunto il $UID al blocco meta_data dell'header X-MSYS-API. Questo passaggio assicura che l'UID sia inserito in ciascun output di evento per l'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 archivio.

Ottenere la versione Archive

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

  1. Crea un sottodominio al quale invierai tutte le email di archivio (duplicato)

  2. Imposta i record DNS appropriati per fare in modo che tutte le email inviate a quel sottodominio vadano a SparkPost

  3. Crea un dominio inbound in SparkPost

  4. Crea un webhook inbound in SparkPost

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

I due link seguenti possono essere usati per aiutarti a guidare questo processo:

  1. Doc tecnico SparkPost: Enabling Inbound Email Relaying & Relay Webhooks

  2. Inoltre, il blog che ho scritto l'anno scorso, Archiving Emails: A How-To Guide for Tracking Sent Mail, 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 utilizzando una connessione SMTP a SparkPost, l'API RESTful non supporta questa funzione.  Probabilmente non è un problema perché la maggior parte delle email che richiedono questo livello di controllo di audit tendono a essere email personalizzate che sono completamente costruite da un'applicazione backend prima che sia necessaria la consegna dell'email.

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

  1. Crea un sottodominio al quale invierai tutte le email di archivio (duplicato)

  2. Imposta i record DNS appropriati per fare in modo che tutte le email inviate a quel sottodominio vadano a SparkPost

  3. Crea un dominio inbound in SparkPost

  4. Crea un webhook inbound in SparkPost

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

I due link seguenti possono essere usati per aiutarti a guidare questo processo:

  1. Doc tecnico SparkPost: Enabling Inbound Email Relaying & Relay Webhooks

  2. Inoltre, il blog che ho scritto l'anno scorso, Archiving Emails: A How-To Guide for Tracking Sent Mail, 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 utilizzando una connessione SMTP a SparkPost, l'API RESTful non supporta questa funzione.  Probabilmente non è un problema perché la maggior parte delle email che richiedono questo livello di controllo di audit tendono a essere email personalizzate che sono completamente costruite da un'applicazione backend prima che sia necessaria la consegna dell'email.

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

  1. Crea un sottodominio al quale invierai tutte le email di archivio (duplicato)

  2. Imposta i record DNS appropriati per fare in modo che tutte le email inviate a quel sottodominio vadano a SparkPost

  3. Crea un dominio inbound in SparkPost

  4. Crea un webhook inbound in SparkPost

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

I due link seguenti possono essere usati per aiutarti a guidare questo processo:

  1. Doc tecnico SparkPost: Enabling Inbound Email Relaying & Relay Webhooks

  2. Inoltre, il blog che ho scritto l'anno scorso, Archiving Emails: A How-To Guide for Tracking Sent Mail, 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 utilizzando una connessione SMTP a SparkPost, l'API RESTful non supporta questa funzione.  Probabilmente non è un problema perché la maggior parte delle email che richiedono questo livello di controllo di audit tendono a essere email personalizzate che sono completamente costruite da un'applicazione backend prima che sia necessaria la consegna dell'email.

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 a livello elevato 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 definita collector) che accetta il flusso di dati Relay_Webhook.

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

if ($_SERVER['REQUEST_METHOD'] === '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.  Quindi ho scritto una piccola funzione che accetta l'array di header e lo scorre per ottenere i dati che ero interessato a memorizzare:

function get_important_headers($headers, &$original_to, &$headerDate, &$subject, &$from) {
    foreach ($headers as $headerGroup) {
        foreach ($headerGroup as $key => $value) {
            if ($key === 'To') {
                $original_to = $value;
            } elseif ($key === 'Date') {
                $headerDate = $value;
            } elseif ($key === 'Subject') {
                $subject = $value;
            } elseif ($key === 'From') {
                $from = $value;
            }
        }
    }
}

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

Memorizzare l'email duplicata in S3

Mi dispiace deluderti, ma non fornirò un tutorial passo-passo su come creare un bucket S3 per archiviare l'email, né descriverò come creare la chiave di accesso necessaria per caricare contenuti sul tuo bucket; ci sono tutorial migliori su questo argomento di quanti potrei mai scriverne.  Ecco un paio di articoli che possono aiutare:

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ò è evidenziare alcune delle impostazioni che ho scelto che riguardano un progetto come questo.

  1. Controllo Accessi.  Non solo è necessario impostare la sicurezza per il bucket, ma è necessario impostare le autorizzazioni per gli elementi stessi.  Nel mio progetto, uso una politica molto aperta di public-read perché i dati di esempio non sono personali e volevo avere facile accesso ai dati.  Probabilmente vorrai una serie di politiche ACL molto più rigide. Ecco un bell'articolo sulle impostazioni ACL: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html

  2. Archiviazione dell'Archivio. In S3 esiste qualcosa chiamato Lifecycle Management.  Questo ti permette di spostare i dati da un tipo di classe di archiviazione S3 a un'altra.  Le diverse classi di archiviazione rappresentano il livello di accesso richiesto ai dati archiviati con costi inferiori associati allo storage che si accede meno. Una buona descrizione delle diverse classi e del passaggio attraverso di esse si trova in una guida AWS chiamata, Transitioning Objects. Nel mio caso, ho scelto di creare un ciclo di vita che spostava ogni oggetto da Standard a Glacier dopo un anno. L'accesso a Glacier è molto più economico rispetto all'archivio S3 standard e mi farà risparmiare sui costi di archiviazione.

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

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

$start = strpos($htmlbody, $inputField);
if ($start !== false) {
    $start = strpos($htmlbody, 'value="', $start);
    if ($start !== false) {
        $start += 7; // Move past 'value="'
        $end = strpos($htmlbody, '"', $start);
        if ($end !== false) {
            $length = $end - $start;
            $UID = substr($htmlbody, $start, $length);
        }
    }
}

* stiamo assumendo che $inputField detenga il valore “ArchiveCode” e sia stato trovato nel mio file config.php.

Con l'UID, possiamo quindi creare il nome file che sarà 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 vuole poco codice per caricare il file.

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

Memorizzare i Meta Data in MySQL

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

  • Un campo di inserimento automatico per data/ora

  • L'indirizzo email di destinazione (RCPT_TO)

  • Il timestamp dall'intestazione DATA dell'email

  • L'intestazione SUBJECT

  • L'intestazione dell'indirizzo email FROM

  • La directory utilizzata nel bucket S3

  • Il nome del file S3 per l'email archiviata

La funzione chiamata MySQLLog all'interno del file di applicazione upload.php esegue i passaggi necessari per aprire il collegamento a MySQL, inserire la nuova riga, testare i risultati e chiudere il collegamento. Aggiungo un altro passaggio per buona misura ed è quello di registrare questi dati in un file di testo. Devo eseguire molti più log per gli errori? Sì. Ma voglio mantenere questo codice leggero per permettergli di funzionare estremamente veloce. A volte, questo codice verrà chiamato centinaia di volte al minuto e deve essere il più efficiente possibile. In futuri aggiornamenti, aggiungerò codice ausiliario che elaborerà i fallimenti e invierà tali fallimenti a un amministratore per il monitoraggio.

Concludendo

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

In future revisioni di questo progetto, mi aspetterei di:

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

  2. Inviare errori di archiviazione a un amministratore quando si verifica un errore di caricamento o di log

  3. Minimizzare la complessità del collettore.

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

  5. Supportare la possibilità di rinviare l'email

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

Connettiamoci con un esperto di Bird.
Scopri tutta la potenza del Bird in 30 minuti.

Inviando, accetti che Bird possa contattarti riguardo ai nostri prodotti e servizi.

Puoi annullare l'iscrizione in qualsiasi momento. Consulta la Informativa sulla Privacy di Bird per i dettagli sul trattamento dei dati.

Azienda

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.

Connettiamoci con un esperto di Bird.
Scopri tutta la potenza del Bird in 30 minuti.

Inviando, accetti che Bird possa contattarti riguardo ai nostri prodotti e servizi.

Puoi annullare l'iscrizione in qualsiasi momento. Consulta la Informativa sulla Privacy di Bird per i dettagli sul trattamento dei dati.

Azienda

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.

Connettiamoci con un esperto di Bird.
Scopri tutta la potenza del Bird in 30 minuti.

Inviando, accetti che Bird possa contattarti riguardo ai nostri prodotti e servizi.

Puoi annullare l'iscrizione in qualsiasi momento. Consulta la Informativa sulla Privacy di Bird per i dettagli sul trattamento dei dati.

R

Raggiungi

G

Grow

M

Manage

A

Automate

Azienda

Newsletter

Rimani aggiornato con Bird attraverso aggiornamenti settimanali nella tua inbox.