
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:
Creazione dell'email duplicata per l'archiviazione
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)
Smontare la struttura JSON per ottenere i componenti necessari
Inviare il corpo dell'email a S3 per la memorizzazione
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.
Da qualche parte nel corpo dell'email, ho inserito il seguente ingresso:<input name="ArchiveCode" type="hidden" value="<<UID>>">
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">
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:
Ora abbiamo un modo per collegare tutti i dati dall'email originale al corpo dell'email di archivio.
Ottenere la versione Archive
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:
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:
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.
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
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:
* 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:
Memorizzare tutti gli eventi di log dell'email originale
Inviare errori di archiviazione a un amministratore quando si verifica un errore di caricamento o di log
Minimizzare la complessità del collettore.
Aggiungere un'interfaccia utente per visualizzare tutti i dati
Supportare la possibilità di rinviare l'email
Nel frattempo, spero che questo progetto sia stato interessante e utile per te; buon invio.