Crearea funcțiilor avansate de e-mail cu IMAP și PHP

Ce veți crea

În acest tutorial, vă voi prezenta câteva exemple din lumea reală despre modul în care puteți utiliza PHP și IMAP pentru a construi noi funcții pentru gestionarea caracteristicilor de e-mail pe care marii furnizori de e-mail nu le-au construit pentru noi.

Interesul meu pentru acest lucru a început în 2010 când am scris douăsprezece idei Gmail pentru a revoluționa e-mail (din nou), dar mai ales ideile pe care le-am dorit au rămas la indemana. La fel de important ca e-mailul, inovarea e-mailului ca aplicație a fost destul de lentă.

Ne innelam prin e-mail, iar gestionarea inbox-urilor ramane o povara grea. Serviciile de poștă și clienții au făcut foarte puțin pentru a ne ajuta în acest sens. Majoritatea e-mailurilor pe care le primim sunt trimise de mașini, nu de oameni, și totuși noi suntem cei care trebuie să procesăm individual toate acestea. 

Analiza e-mail-ului meu a arătat că primesc e-mailuri de la mai mult de 230 de expeditori automați, cu mult mai puțini oameni reali. Am fost obosit să construiesc filtre în Gmail și să completez o multitudine de formulare de dezabonare. Am vrut să am mai mult control asupra gestionării e-mailului meu și simplificării vieții mele.

În final, anul trecut, am decis să construiesc caracteristicile de care aveam nevoie. Rezultatul este Simplify Email (SE), o mică aplicație web pe care o puteți găzdui, care oferă o varietate de funcții noi de e-mail cool, toate pe care le puteți verifica pe site-ul proiectului.

Cea mai tare lucru despre SE este că este o platformă pentru citirea, analizarea, direcționarea și administrarea e-mailului - posibilitățile abundă. Simplificarea e-mailului este în esență un loc de joacă programabil pentru "hacking" propriul e-mail.

Vă voi trece prin codul a trei exemple din SE care folosesc PHP, IMAP și MySQL pentru a lucra cu e-mail:

  1. Verificați mesajele primite și filtrarea mesajelor
  2. Implementarea unei provocări pe lista albă a expeditorilor necunoscuți
  3. Raportarea e-mailului fără răspuns

Acest tutorial vă va oferi cu siguranță un început la scrierea codului IMAP în PHP. Dar puteți lucra, de asemenea, direct cu baza de date Simplify Email. Puteți achiziționa codul pentru doar 10 $ și există o versiune mai veche cu sursă deschisă (care nu are unele dintre caracteristicile pe care le descriem mai jos). Ghidurile de instalare sunt furnizate pentru configurații tipice Linux. De asemenea, ofer imagini pre-instalate la Oceanul Digital pentru 25 de dolari, precum și o instalație de valet cu handheld. SE este scrisă în PHP, în Cadrul Yii. 

Rețineți că nu veți putea accesa majoritatea serverelor de e-mail prin intermediul mașinii dvs. de dezvoltare locală decât dacă compilați o bibliotecă sigură IMAP pentru PHP. Acesta este unul dintre motivele pentru care încurajez oamenii să ruleze Simplify Email în picături la Oceanul Digital. Există, de asemenea, câteva trucuri pentru a obține securitatea contului Google pentru a vă permite să vă conectați prin intermediul IMAP.

Lucrul cu IMAP

Cum funcționează e-mailurile simplificate

Cu SE, puteți continua să utilizați clientul dvs. de e-mail ales de pe Web și de pe dispozitivele dvs. mobile. Nu trebuie să schimbați niciun fel de aplicații sau obiceiuri personale. SE accesează conturile dvs. de e-mail în spatele scenei prin intermediul IMAP; acționând ca un asistent personal inteligent, SE vă pre-procesează e-mailurile, deplasând mesajele către locurile corespunzătoare bazându-vă pe tot ceea ce le-ați spus.

Când un mesaj sosește de la un expeditor familiar, SE îl mută în dosarul pe care l-ați specificat. Atunci când sosiți dintr-un expeditor necunoscut pentru prima dată, îl mutați în dosarul de examinare. 

La fiecare două ore (sau la o frecvență pe care o alegeți), SE vă va trimite un rezumat al locului în care a mutat mesajele dvs. și a mesajelor care sunt în revistă. Rețineți că link-urile pentru expeditorii de instruire sunt incluse în dosarul de examinare, ceea ce face destul de ușor să antrenați SE în timp.

În orice moment, puteți naviga în dosarul de examinare - nu trebuie să așteptați ca digestul să ajungă. Dar avantajul SE este că nu mai trebuie să răsfoiți folderele; puteți citi doar digestul dvs. pentru a obține o vizualizare a e-mailului pe care l-ați primit și pentru a instrui noii expeditori.

1. Verificați mesajele primite și filtrarea mesajelor

SE utilizează mai multe sarcini cron pentru a funcționa în fundal pe serverul dvs. Fiecare este chemat de la DaemonController.php.

Primul, processInbox, este numit frecvent și trebuie să funcționeze rapid - sarcina sa este de a afișa e-mailurile și de a le scoate din Inbox cât mai repede posibil și în dosarul triaj, numit directorul de filtrare. 

Al doilea, processFiltering, este mai intensă în proces și efectuează operații mai profunde pe e-mail, transferând în cele din urmă mesaje către destinația finală.

Metoda ProcessInbox

Sarcini cron solicită processInbox in mod regulat:

funcția publică funcțiaInbox () // mută mesajele primite în @filtering // rulează frecvent $ r = new Remote (); $ R-> processInbox (); 

Pentru fiecare cont, vă decriptați acreditările de poștă electronică și apoi utilizați imap_open pentru a crea un flux IMAP în dosarul dvs. de poștă electronică:

funcția publică deschisă ($ account_id, $ mailbox = ", $ options = NULL) // deschide dosarul într-un cont IMAP $ account = cont :: model () -> findByPk ($ account_id); $ this-> hostname = contul-> adresa; dacă (! stristr ($ this-> hostname, '')) $ this-> hostname = ''. $ this-> hostname. -> getCredentials ($ account-> cred); if ($ account-> provider == Account :: PROVIDER_ICLOUD) // icloud acceptă doar o parte a căsuței poștale, de exemplu stevejobs vs. [email protected] $ temp = explode (' @ $, $ cred [0]), $ cred [0] = $ temp [0]; $ this-> stream = imap_open ($ this-> hostname, $ mailbox, $ cred [0], $ cred [1] ], $ optiuni, 1) sau mor ('Nu se poate conecta la serverul de mail - account_id:'. $ account_id. "print_r (imap_errors ()));  

În processInbox, folosim funcțiile bibliotecii PHP imap_search și imap_fetch_overview pentru a prelua o serie de mesaje:

// searchup folder_id din INBOX-ul acestui cont $ folder_id = Folder :: model () -> lookup ($ account_id, $ this-> path_inbox); $ This-> deschis ($ ACCOUNT_ID, $ this-> path_inbox); $ Cnt = 0; $ message_limit = 50; // spargeți după n mesaje pentru a preveni ecourile de timp "Sort din: '.date (" j F Y ", $ tstamp); // imap_search formatul datei 30 noiembrie 2013 $ recent_messages = @imap_search ($ this-> stream, 'FROM' '.date ("j FY", $ tstamp). "", SE_UID); dacă ($ recent_messages === false) continuați; // să faceți - continuați în următorul cont $ result = imap_fetch_overview ($ this-> stream, implode (',', array_slice ($ recent_messages, 0, $ message_limit)), FT_UID); 

Apoi, procesăm seria de mesaje din căsuța de e-mail:

foreach ($ rezultat ca element $) if (! $ this-> checkExecutionTime ($ time_start)) pauză; // primi msg header și flux uid $ msg = $ this-> parseHeader ($ item); 

Iată o versiune adaptată a codului de parcurgere a antetului public IMAP, care adună informațiile suplimentare pe care SE le are nevoie pentru o varietate de sarcini. Practic, utilizează imap_rfc822_parse_adrlist pentru a determina informațiile despre destinatar, ID-ul mesajului, subiectul și marcajele de timp (sau informațiile despre expeditor atunci când scanează dosarul trimis):

 funcția publică parseHeader ($ header) // parses header object returnat de la imap_fetch_overview dacă (! isset ($ header-> from)) return false;  altceva $ from_arr = imap_rfc822_parse_adrlist ($ header-> de la, 'gmail.com'); $ fi = $ din_arr [0]; $ msg = array ("uid" => (isset ($ header-> uid))? $ header-> uid: 0, "personal" -> personal): "", "email" => (isset ($ fi-> căsuță poștală) && isset ($ fi-> host)) $ $ fi-> "," căsuța poștală "=> (isset ($ fi-> gazdă))? $ fi-> gazdă:" "," subject "=> (isset ($ header-> subiect))? @imap_utf8 ($ header-> subiect) > mesaj_id: "", "in_reply_to" => (isset ($ header-> in_reply_to))? header-> in_reply_to: > udate: 0, "date_str" => (isset ($ antet-> data))? $ header-> date: ""); // handles fetch cu paragraful header uid și rfc dacă $ msg ['udate'] == 0 && isset ($ header-> date)) $ msg ['udate'] = strtotime ($ header-> date);  $ msg ['rx_email'] = "; $ msg ['rx_personal'] ="; $ msg ['rx_mailbox'] = "; $ msg ['rx_host'] ="; dacă (isset ($ header-> to)) $ to_arr = imap_rfc822_parse_adrlist ($ header-> to, 'gmail.com'); $ to_info = $ to_arr [0]; dacă isset ($ to_info-> mailbox) && isset ($ to_info-> gazdă)) $ msg ['rx_email'] = $ to_info-> căsuța poștală. '.' $ to_info-> host;  dacă (isset ($ to_info-> personal)) $ msg ['rx_personal'] = $ to_info-> personal; dacă (isset ($ to_info-> mailbox)) $ msg ['rx_mailbox'] = $ to_info-> căsuța poștală; dacă (isset ($ to_info-> gazdă)) $ msg ['rx_host'] = $ to_info-> host;  return $ msg; 

Creăm înregistrări pentru expeditor și plicul mesajului în baza noastră de date:

 // ignorați orice mesaje de sistem dacă ($ msg ['email'] == $ system_email) continuați; // dacă udate este prea vechi, săriți msg if (time () - $ msg ['udate']> $ this-> scan_seconds) continuați; // skip msg // implicit acțiune $ action = self :: ACTION_MOVE_FILTERED; $ isNew = $ s-> isNew ($ cont_id, $ msg ["email"]); // căutați expeditorul, dacă este nou, creați-l $ sender_id = $ s-> adăugați ($ user_id, $ account_id, $ msg ["personal"], $ msg ["mailbox"], 0); $ sender = Expeditor :: model () -> findByPk ($ sender_id); // creați un mesaj în db dacă este necesar $ message_id = $ m-> add ($ user_id, $ account_id, 0, $ sender_id, $ msg ['message_id'], $ msg ['subject' '], $ msg [' in_reply_to ']); $ message = Mesaj :: model () -> findByPk ($ message_id); 

În cazul în care expeditorul este nou pentru noi (necunoscut), vom trimite un e-mail de provocare pe lista albă (vom vorbi mai multe despre provocările pe lista albă în următoarea secțiune de mai jos):

dacă ($ isNew) $ this-> challengeSender ($ user_id, $ account_id, $ sender, $ message); 

Apoi, vom determina dacă utilizatorul ar fi putut trage un mesaj dintr-un alt dosar înapoi în căsuța de e-mail, intenționând să îl instruiască prin drag and drop. Dacă da, am stabilit instruirea pentru acest expeditor în căsuța de e-mail. Cu alte cuvinte, data viitoare, dorim doar să direcționăm mesajele de la acest expeditor către căsuța de e-mail:

 dacă ($ message ['status'] == Mesaj :: STATUS_FILTERED || $ message ['status'] == Mesaj :: STATUS_REVIEW || ($ message ['status'] == Mesaj :: STATUS_TRAINED && $ message [ 'folder_id'] <> $ folder_id) || ($ message ['status'] == Mesaj :: STATUS_ROUTED && $ message ['folder_id'] <> $ folder_id))  :: ACTION_TRAIN_INBOX;  altfel dacă (($ message ['status'] == Message :: STATUS_TRAINED || $ message ['status'] == Mesaj :: STATUS_ROUTED) && $ message ['folder_id'] == $ folder_id) // dacă sunteți pregătiți deja sau trimiși în căsuța de e-mail, săriți-o $ action = self :: ACTION_SKIP; echo "instruit anterior, săriți"; lb (); continua;  

Dacă nu, pregătim să mutăm mesajul în dosarul Filtrare pentru o prelucrare ulterioară. În primul rând, putem trimite notificări la telefonul utilizatorului dacă există o potrivire a expeditorului sau o potrivire a cuvintelor cheie pentru notificări (și nu este o oră liniștită):

 dacă ($ action == self :: ACTION_MOVE_FILTERED) $ cnt + = 1; dacă ($ sender-> exclude_quiet_hours == Sender :: EQH_YES sau! $ this-> isQuietHours ($ user_id)) // trimite notificări pentru smartphone bazate pe expeditor dacă ($ sender-> alert == Sender :: ALERT_YES) $ this-> notifică ($ expeditor, mesajul $, Monitor :: NOTIFY_SENDER);  // trimiteți notificări pe baza cuvintelor cheie dacă (AlertKeyword :: model () -> scanare ($ msg)) $ this-> notify ($ expeditor, $ message, Monitor :: NOTIFY_KEYWORD);  // mutare imap msg la + Filtrare ecou 'Mutarea la + Filtrare'; lb (); // $ result = @imap_mail_move ($ acest-> flux, $ msg ['uid'], $ this-> path_filtering, CP_UID); $ result = $ this-> messageMoveHandler ($ msg ['uid'], $ this-> path_filtering, false); dacă ($ rezultat) echo 'a fost mutat
„; $ M '> setStatus ($ message_ID, Mesaj :: STATUS_FILTERED);

Dacă mesajul a fost tras în căsuța de e-mail, vom actualiza setările de antrenament:

altfel dacă ($ action == self :: ACTION_TRAIN_INBOX) // setați expeditorul folder_id în căsuța de e-mail echo 'Trecere la Inbox'; lb (); $ M '> setStatus ($ message_ID, Mesaj :: STATUS_TRAINED); // numai expeditorul trenului atunci când mesajul este mai recent decât ultima setare dacă ($ msg ['udate']> = $ expeditor ['last_trained']) $ s-> setFolder ($ sender_id, $ folder_id); 

Metoda procesului de filtrare

Se numește metoda secundară de procesare processFiltering, De asemenea, în DaemonController.php. Ea face mai multe aspecte consumatoare de timp de a muta mesajele la dosarele corespunzătoare:

funcția publică funcțiaIndex () // procesează mesajele din @Filtering în dosarele corespunzătoare $ r = new Remote (); $ R-> processFiltering (); // Înregistrați marca de timp a cronjob pentru monitorizarea $ file = file_put_contents ('./ protected / runtime / cronstamp.txt', time (), FILE_USE_INCLUDE_PATH);  

Această metodă deschide contul dvs. de e-mail pentru a căuta mesajele recente și pentru a aduna date despre ele. De asemenea, utilizează imap_search, imap_fetch_overview și parseHeader:

$ tstamp = timp () - (7 * 24 * 60 * 60); // 7 zile în urmă $ recent_messages = @imap_search ($ this-> stream, 'FROM' '.date ("j FY", $ tstamp). "", SE_UID); dacă ($ recent_messages === false) continuați; // să faceți - continuați în următorul cont $ result = imap_fetch_overview ($ this-> stream, implode (',', array_slice ($ recent_messages, 0, $ message_limit)), FT_UID); foreach ($ rezultat ca element $) $ cnt + = 1; dacă (! $ this-> checkExecutionTime ($ time_start)) se rupe; // primi msg header și flux uid $ msg = $ this-> parseHeader ($ item); 

Buclele primare de procesare pentru fiecare mesaj din dosarul de filtrare sunt destul de detaliate. Mai întâi, ne uităm la adresa destinatarului, deoarece SE permite oamenilor să instruiască dosarele după adresa destinatarului, de ex. mesajele către domeniul happyvegetarian.com merg la dosarul vegetarian:

 // Setați acțiunea implicită pentru a vă deplasa în directorul de revizuire $ action = self :: ACTION_MOVE_REVIEW; $ destination_folder = 0; // căutați și creați destinatarul $ recipient_id = $ r-> adăugați ($ user_id, $ account_id, $ msg ['rx_email'], 0); $ routeByRx = $ acest-> routeByRecipient ($ recipient_id); dacă ($ routeByRx! == false) $ action = $ routeByRx-> acțiune; $ destination_folder = $ routeByRx-> folderul destinație;  

Apoi căutăm expeditorul și creăm o înregistrare nouă în baza de date (dacă este necesar). Dacă există instruire pentru expeditor, putem seta dosarul de destinație:

 // căutați expeditorul, dacă este nou, creați-l $ sender_id = $ s-> adăugați ($ user_id, $ account_id, $ msg ["personal"], $ msg ["mailbox"], 0); $ sender = Expeditor :: model () -> findByPk ($ sender_id); // dacă destinația expeditorului este cunoscută, ruta către dosar dacă ($ destination_folder == 0 && $ sender ['folder_id']> 0) $ action = auto :: ACTION_ROUTE_FOLDER; $ destination_folder = $ expeditor ['folder_id'];  

Dacă un expeditor (nou) neinstruit s-a verificat printr-o provocare albă (despre care vom discuta în următoarea secțiune de mai jos), atunci vom direcționa acest mesaj către căsuța de e-mail:

// expeditorii verificați pe lista albă merg în căsuța poștală dacă ($ sender-> is_verified == 1 && $ sender ['folder_id'] == 0 && UserSetting :: model () -> useWhitelisting ($ user_id))  intrări $ action = auto :: ACTION_ROUTE_FOLDER; $ destination_folder = Folder :: model () -> căutare ($ cont_id, $ this-> path_inbox); 

Apoi, vom crea o intrare de mesaj în baza de date cu informații despre acest mesaj:

 // creați un mesaj în db $ message = Mesaj :: model () -> findByAttributes (array ('message_id' => $ msg ['message_id'])); dacă (! empty ($ message)) // mesajul există deja, $ message_id = $ message-> id;  altceva $ message_id = $ m-> add ($ user_id, $ cont_id, 0, $ sender_id, $ msg ['message_id'], $ msg ['subject'], 'in_reply_to']);  

Dacă este de la un expeditor necunoscut, neavizat, putem muta mesajul în dosarul de examinare. Dosarul de examinare conține toate mesajele de la expeditorii pe care nu le recunoaștem.

Dacă mesajul este de la un expeditor cunoscut și avem o destinație în minte, îl putem mișca atâta timp cât nu este o oră liniștită (și nu deranjați este oprit):

 dacă ($ recipient_id! == false) $ m-> setRecipient ($ message_id, $ recipient_id); dacă ($ action == self :: ACTION_MOVE_REVIEW) echo 'Mutarea la + Filtrare / Revizuire'; lb (); // $ result = @imap_mail_move ($ acest-> flux, $ msg ['uid'], $ this-> path_review, CP_UID); $ result = $ this-> messageMoveHandler ($ msg ['uid'], $ this-> path_review, false); dacă ($ rezultat) echo 'a fost mutat
„; $ M '> setStatus ($ message_ID, Mesaj :: STATUS_REVIEW); altfel dacă ($ action == self :: ACTION_ROUTE_FOLDER || $ action == self :: ACTION_ROUTE_FOLDER_BY_RX) // numele directorului de căutare după folder_id $ folder = Folder :: model () -> findByPk ($ destination_folder); // Daca inbox si ora linistita, nu traseaza acum daca strtolower ($ folder ['name']) == 'inbox' si $ sender-> exclude_quiet_hours == Sender :: EQH_NO si $ this-> isQuietHours ( $ user_id)) continuați; echo 'Mutarea la'. $ folder ['name']; lb (); $ mark_read = Folder :: model () -> isMarkRead ($ folder ['mark_read']) || Expeditor :: model () -> isMarkRead ($ expeditor [ 'mark_read']); // $ result = @imap_mail_move ($ acest-> flux, $ msg ['uid'], $ folder ['name'], CP_UID); $ result = $ this-> messageMoveHandler ($ msg ['uid'], $ folder ['nume'], $ mark_read); dacă ($ rezultat) echo 'a fost mutat
„; $ M '> setStatus ($ message_ID, Mesaj :: STATUS_ROUTED); $ M-> setFolder ($ message_ID, $ destination_folder);

În timpul orelor de liniște, mesajele sunt păstrate în principal în dosarul de filtrare.

La fiecare câteva ore, un proces diferit va construi digestul mesajului folosind înregistrările tabelului de mesaje pentru a determina ce e-mailuri au fost primite și filtrate recent și despre modul în care au fost dirijate.

2. Implementarea unei provocări pe lista albă a expeditorilor necunoscuți

Scopul provocării de pe lista albă este păstrarea oricărui mesaj de la un expeditor necunoscut, de ex. eventual un bot de marketing sau un spammer, din extrasul tău. SE plasează poșta de la expeditori necunoscuți în dosarul de examinare. Cu toate acestea, dacă vă întoarceți pe lista albă, trimitem un e-mail de provocare care dă expeditorului o șansă de a verifica dacă este uman. Dacă răspund, vom muta mesajul în căsuța de e-mail. Dacă e-mailul se dovedește a fi nedorit, puteți să introduceți mesajul din digest sau să îl trageți în orice folder pe care doriți să îl instruiți.

Utilizatorul poate activa și dezactiva lista albă în setări:

Pentru a implementa lista albă, trimitem provocări prin e-mail ori de câte ori e-mailul vine de la un nou expeditor:

dacă ($ isNew) $ this-> challengeSender ($ user_id, $ account_id, $ sender, $ message); 

ChallengeSender trimite un link codat utilizatorului pentru ca aceștia să facă clic. Avem, de asemenea, unele protecții pentru a ne asigura că nu ne prindem într-o buclă de e-mail cu un mesaj în afara biroului:

 funcția publică funcțiaSender ($ user_id, $ account_id, $ sender, $ message) // comanda de e-mail albă $ yg = new Yiigun (); $ ac = cont :: model () -> findByPk ($ cont_id); dacă (! empty ($ ac ['challenge_name'])) $ din = $ ac ['challenge_name']. ' mg_domain '>.'; altul $ from = 'Filtru mg_domain '>.'; $ cred = Cont :: model () -> getCredentials ($ ac-> cred); $ cont_email = $ cred [0]; unset ($ CRED); // safety: nu verifică nici un e-mail recent dacă ($ sender-> last_emailed> (time () - (48 * 60 * 60))) return false; dacă $ sender-> isBot ($ sender ['email'])) // să facă - poate, de asemenea, să stabilească această persoană în bloc în mod implicit return false;  $ / link-ul / y / $ / link-ul / '/' / ' . $ Message> udate; $ subject = 'Verificați mesajul la care ați trimis mesajul' $ account_email; $ = Corp“

Bună,

Încerc să reduc e-mailurile nesolicitate. Ați putea verifica adresa dvs. de e-mail făcând clic pe linkul de mai jos:
'$ Link-ul.'

Verificarea adresei dvs. de e-mail vă va ajuta să accelerați mesajul în căsuța de e-mail. multumesc pentru asistenta!

„; $ yg-> send_html_message ($ din, $ sender ['email'], $ subiect, $ body); // actualizați last_emailed $ sender-> touchLastEmailed ($ sender-> id);

Apoi, dacă destinatarul face clic pe linkul codificat, le verificăm în baza de date. Controlorul de expeditor procesează aceste solicitări și verifică valabilitatea acestora:

 funcția publică funcțiaVerificați ($ s = 0, $ m = 0, $ u = 0) // verificați dacă adresa de email sigură din digest este validă, conectați-vă la utilizator, afișați msg $ sender_id = $ s; $ message_id = $ m; $ udate = $ u; $ msg = Mesaj :: model () -> findByPk ($ message_id); dacă ! empty ($ msg) && $ msg-> sender_id == $ sender_id && $ msg-> udate == $ udate) $ result = 'Vă mulțumim pentru asistență. Voi răspunde la e-mailul dvs. cât mai curând posibil. '; $ a = nou Avansat (); $ A-> verifySender ($ msg-> ACCOUNT_ID, $ SENDER_ID);  else $ result = 'Ne pare rău, nu am putut confirma adresa dvs. de e-mail.';  $ this-> render ('verificare', array ('rezultat' => $ rezultat,)); 

Aceasta ne spune buclelor noastre de procesare să mute acest mesaj și mesajele viitoare de la acest expeditor în căsuța de e-mail.

3. Raportarea e-mailului fără răspuns

Uneori vă ajută să vedeți un rezumat al mesajelor pe care le-ați trimis dar nu le-ați primit un răspuns. Pentru a le identifica, Simplify Email monitorizează mesajele care au fost trimise dar nu au primit un răspuns.

Fiecare mesaj pe care îl primim conține un id unic, numit message_id (parte din specificația IMAP). Adesea arata astfel:

ID mesaj: 

Mai mult, atunci când mesajele sunt trimise ca răspuns la alte mesaje, acestea au un mesaj in_reply_to câmp care se leagă de original message_ID.

Deci, folosim o interogare SQL pentru a găsi toate mesajele primite care nu au un mesaj de răspuns corespunzător referindu-le la acestea message_ID. Pentru aceasta, utilizăm un JOINȚE OUTER STÂNGA în cazul în care nu există in_reply_to id:

funcția publică getUnanswered ($ account_id, $ mode = 0, $ range_days = 7) if ($ mode == 0) $ subject_compare = 'nu'; altul $ subject_compare = "; $ query = Yii :: app () -> db-> createCommand (" SELECT fi_sent_message.id, fi_sent_message.recipient_id ca sender_id, fi_sent_message.subject, fi_sent_message.udate, fi_message.in_reply_to, fi_sent_message.message_id FROM fi_sent_message LEFT OUTOUN JOIN fi_message ON fi_message.in_reply_to = fi_sent_message.message_id WHERE fi_sent_message.account_id = ". $ account_id" ȘI fi_message.in_reply_to este null și fi_sent_message.udate> ". (time () - (3600 * 24 * $ range_days) ) "și fi_sent_message.subject". $ subject_compare. "ca 'Re:%' ORDER BY fi_sent_message.udate DESC") -> queryAll ();

Noi folosim $ subject_compare mod de a face diferența între mesajele trimise care nu au primit răspuns și răspunsurile trimise la un fir care nu a primit răspuns. Iată raportul de mesaj fără răspuns în contul dvs.:

SE oferă, de asemenea, aceste informații ca un digest opțional, numit digestul nevalorificat de e-mail. Puteți să o primiți în fiecare zi, la fiecare câteva zile sau în fiecare săptămână.

De asemenea, folosim tabelarea SQL asemănătoare cu Google Charts pentru a furniza rapoarte despre cât de frecvent anumite persoane vă trimit prin e-mail:

 ($ account_id, $ range = 30, $ limit = 100) $ result = Yii :: app () -> db-> createCommand ('SELECT fi_sender.personal, fi_sender.email, count (sender_id) FROM fi_message LEFT JOIN fi_sender ON fi_sender.id = fi_message.sender_id WHERE fi_sender.account_id =: cont_id AND fi_message.created_at> DATE_SUB (ACUM (), INTERVAL: interval DAY) GROUP BY sender_id ORDER BY cnt desc LIMIT: limit ') -> bindValue ( 'interval', intervalul $) -> bindValue ( 'ID_cont', $ ACCOUNT_ID) -> bindValue ( 'limită', $ limita) -> queryAll (); returneaza rezultatul $;  

Voi scrie mai multe despre Google Charts for Tuts + în curând. 

Pasii urmatori

Sper că ați găsit Simplify Email destul de interesant pentru a vă încerca să faceți o programare PHP IMAP. Există atât de multe caracteristici interesante pe care le puteți construi fără a fi nevoie ca furnizorii mari de e-mail să facă ceva nou.

Dacă aveți întrebări sau corecții, vă rugăm să le postați în comentarii. Dacă doriți să respectați viitoarele tutoriale Tuts + și alte serii, vă rugăm să urmăriți @reifman sau să vizitați pagina autorului meu. De asemenea, puteți să mă contactați aici.

Link-uri conexe

Iată câteva linkuri suplimentare pe care le puteți considera utile:

  • Simplificați e-mailul
  • Introducere în simplificarea e-mailului (video)
  • Doisprezece idei Gmail pentru a revoluționa e-mailul (din nou) 
  • Acoperirea de a simplifica e-mail-ul în BoingBoing aici și aici
  • Referință PHP IMAP
  • Introducere în Cadrul Yii (Tuts +)
Cod