() translation by (you can also view the original English article)
In diesem Tutorial werde ich Ihnen einige Beispiele aus der Praxis zeigen, wie Sie mit PHP und IMAP neue Funktionen zum Verwalten Ihrer E-Mails erstellen können - Funktionen, die die großen E-Mail-Anbieter nicht für uns entwickelt haben.
Mein Interesse daran begann im Jahr 2010, als ich zwölf Google Mail-Ideen zur Revolutionierung von E-Mails (erneut) geschrieben habe, aber die meisten Ideen, die ich mir gewünscht habe, blieben unerreichbar. So wichtig E-Mails auch sind, die Innovation von E-Mails als Anwendung war recht langsam.
Wir ertrinken in E-Mails und die Verwaltung unserer Posteingänge bleibt eine schwere Belastung. Postdienste und Kunden haben sehr wenig getan, um uns dabei zu helfen. Die meisten E-Mails, die wir erhalten, werden von Maschinen gesendet, nicht von Personen, und dennoch sind wir diejenigen, die alles einzeln verarbeiten müssen.
Die Analyse meiner eigenen E-Mail ergab, dass ich E-Mails von mehr als 230 automatisierten Absendern erhielt, weit weniger von tatsächlichen Personen. Ich hatte es satt, Filter in Google Mail zu erstellen und unzählige Abmeldeformulare auszufüllen. Ich wollte mehr Kontrolle über die Verwaltung meiner E-Mails und die Vereinfachung meines Lebens haben.
Schließlich habe ich mich im vergangenen Jahr entschlossen, die Funktionen zu entwickeln, die ich brauchte. Das Ergebnis ist Simplify Email (SE), eine kleine Web-App, die Sie selbst hosten können und die eine Vielzahl cooler neuer E-Mail-Funktionen bietet, die Sie alle auf der Projektwebsite abrufen können.
Das Beste an SE ist, dass es eine Plattform zum Lesen, Analysieren, Weiterleiten und Verwalten Ihrer E-Mails ist - die Möglichkeiten sind vielfältig. E-Mail vereinfachen ist im Wesentlichen ein programmierbarer Spielplatz zum "Hacken" Ihrer eigenen E-Mail.
Ich werde Sie durch den Code von drei Beispielen von SE führen, die PHP, IMAP und MySQL verwenden, um mit E-Mails zu arbeiten:
- Überprüfen Sie Ihren Posteingang und filtern Sie Nachrichten
- Implementierung einer Whitelist-Herausforderung für unbekannte Absender
- Unbeantwortete E-Mails melden
Dieses Tutorial gibt Ihnen definitiv einen Vorsprung beim Schreiben von IMAP-Code in PHP. Sie können aber auch direkt mit der Codebasis "E-Mail vereinfachen" arbeiten. Sie kaufen den Code für nur 10 US-Dollar und es gibt eine ältere Open-Source-Version (der einige der unten beschriebenen Funktionen fehlen). Installationshandbücher werden für typische Linux-Konfigurationen bereitgestellt. Ich biete auch vorinstallierte Images bei Digital Ocean für 25 US-Dollar sowie eine Handheld-Valet-Installation an. SE ist in PHP im Yii Framework geschrieben.
Beachten Sie, dass Sie über Ihren lokalen Entwicklungscomputer nur dann auf die meisten E-Mail-Server zugreifen können, wenn Sie eine sichere IMAP-Bibliothek für PHP kompilieren. Dies ist einer der Gründe, warum ich Menschen dazu ermutige, Simplify Email in Tröpfchen bei Digital Ocean auszuführen. Es gibt auch einige Tricks, um die Sicherheit Ihres Google-Kontos über IMAP zu gewährleisten.
Arbeiten mit IMAP
Wie man E-Mails vereinfachen kann
Mit SE können Sie Ihren E-Mail-Client Ihrer Wahl sowohl im Web als auch auf Ihren Mobilgeräten weiterhin verwenden. Sie müssen keine Apps oder persönlichen Gewohnheiten ändern. SE greift über IMAP hinter den Kulissen auf Ihre E-Mail-Konten zu. Als intelligenter persönlicher Assistent verarbeitet SE Ihre E-Mails vor und verschiebt Nachrichten basierend auf allem, was Sie gesagt haben, an die entsprechenden Stellen.
Wenn eine Nachricht von einem vertrauten Absender eingeht, verschiebt SE sie in den von Ihnen angegebenen Ordner. Wenn jemand zum ersten Mal von einem unbekannten Absender kommt, wird er in den Überprüfungsordner verschoben.
Alle paar Stunden (oder mit einer von Ihnen gewählten Häufigkeit) sendet SE Ihnen eine Zusammenfassung darüber, wohin Ihre Nachrichten verschoben wurden und welche Nachrichten überprüft werden. Beachten Sie, dass für den Überprüfungsordner Links für Schulungssender enthalten sind, die das Trainieren von SE im Laufe der Zeit recht einfach machen.



Sie können jederzeit Ihren Überprüfungsordner durchsuchen - Sie müssen nicht warten, bis der Digest eintrifft. Der Vorteil von SE ist jedoch, dass Sie Ihre Ordner nicht mehr durchsuchen müssen. Sie können einfach Ihren Digest lesen, um einen Blick auf die E-Mail zu erhalten, die Sie erhalten haben, und neue Absender schulen.
1. Überprüfen Sie Ihren Posteingang und filtern Sie Nachrichten
SE verwendet mehrere Cron-Tasks, um im Hintergrund auf Ihrem Server zu arbeiten. Jeder wird von DaemonController.php
aufgerufen.
Der erste, processInbox
, wird häufig aufgerufen und muss schnell funktionieren. Seine Aufgabe besteht darin, E-Mails zu überprüfen und so schnell wie möglich aus dem Posteingang in den Triage-Ordner zu verschieben, der als Filterordner bezeichnet wird.
Das zweite, processFiltering
, ist prozessintensiver und führt tiefere Operationen für E-Mails durch, wodurch Nachrichten letztendlich an ihr endgültiges Ziel verschoben werden.
Die ProcessInbox-Methode
Die Cron-Tasks rufen regelmäßig processInbox
auf:
1 |
public function actionInbox() { |
2 |
|
3 |
// moves inbox messages to @filtering
|
4 |
// runs frequently
|
5 |
$r = new Remote(); |
6 |
$r->processInbox(); |
7 |
|
8 |
}
|



Für jedes Konto entschlüsseln wir Ihre E-Mail-Anmeldeinformationen und verwenden dann imap_open, um einen imap_open für Ihren Posteingangsordner zu erstellen:
1 |
public function open($account_id, $mailbox='',$options=NULL) { |
2 |
// opens folder in an IMAP account
|
3 |
$account = Account::model()->findByPk($account_id); |
4 |
$this->hostname = $account->address; |
5 |
if (!stristr($this->hostname,'{')) |
6 |
$this->hostname = '{'.$this->hostname.'}'; |
7 |
$cred = Account::model()->getCredentials($account->cred); |
8 |
if ($account->provider == Account::PROVIDER_ICLOUD) { |
9 |
// icloud accepts only name part of mailbox e.g. stevejobs vs. stevejobs@icloud.com
|
10 |
$temp = explode('@',$cred[0]); |
11 |
$cred[0]=$temp[0]; |
12 |
}
|
13 |
$this->stream = imap_open($this->hostname.$mailbox,$cred[0],$cred[1],$options,1) or die('Cannot connect to mail server - account_id:'.$account_id .' '.print_r(imap_errors())); |
14 |
}
|
In processInbox
verwenden wir die PHP-Bibliotheksfunktionen imap_search und imap_fetch_overview, um ein Array von Nachrichten abzurufen:
1 |
// lookup folder_id of this account's INBOX
|
2 |
$folder_id = Folder::model()->lookup($account_id,$this->path_inbox); |
3 |
$this->open($account_id,$this->path_inbox); |
4 |
$cnt=0; |
5 |
$message_limit= 50; // break after n messages to prevent timeout |
6 |
echo 'Sort since: '.date("j F Y",$tstamp); |
7 |
// imap_search date format 30 November 2013
|
8 |
$recent_messages = @imap_search($this->stream, 'SINCE "'.date("j F Y",$tstamp).'"',SE_UID); |
9 |
if ($recent_messages===false) continue; // to do - continue into next account |
10 |
$result = imap_fetch_overview($this->stream, implode(',',array_slice($recent_messages,0,$message_limit)),FT_UID); |
Dann verarbeiten wir das Nachrichtenarray im Posteingang:
1 |
foreach ($result as $item) { |
2 |
if (!$this->checkExecutionTime($time_start)) break; |
3 |
// get msg header and stream uid
|
4 |
$msg = $this->parseHeader($item); |
Hier ist eine angepasste Version des öffentlich verfügbaren IMAP-Header-Parsing-Codes, der die zusätzlichen Informationen sammelt, die SE für eine Vielzahl von Aufgaben benötigt. Grundsätzlich wird imap_rfc822_parse_adrlist verwendet, um Empfängerinformationen, Nachrichten-ID, Betreff und Zeitstempel (oder Absenderinformationen beim Scannen des gesendeten Ordners) zu ermitteln:
1 |
public function parseHeader($header) { |
2 |
// parses header object returned from imap_fetch_overview
|
3 |
if (!isset($header->from)) { |
4 |
return false; |
5 |
} else { |
6 |
$from_arr = imap_rfc822_parse_adrlist($header->from,'gmail.com'); |
7 |
$fi = $from_arr[0]; |
8 |
$msg = array( |
9 |
"uid" => (isset($header->uid)) |
10 |
? $header->uid : 0, |
11 |
"personal" => (isset($fi->personal)) |
12 |
? @imap_utf8($fi->personal) : "", |
13 |
"email" => (isset($fi->mailbox) && isset($fi->host)) |
14 |
? $fi->mailbox . "@" . $fi->host : "", |
15 |
"mailbox" => (isset($fi->mailbox)) |
16 |
? $fi->mailbox : "", |
17 |
"host" => (isset($fi->host)) |
18 |
? $fi->host : "", |
19 |
"subject" => (isset($header->subject)) |
20 |
? @imap_utf8($header->subject) : "", |
21 |
"message_id" => (isset($header->message_id)) |
22 |
? $header->message_id : "", |
23 |
"in_reply_to" => (isset($header->in_reply_to)) |
24 |
? $header->in_reply_to : "", |
25 |
"udate" => (isset($header->udate)) |
26 |
? $header->udate : 0, |
27 |
"date_str" => (isset($header->date)) |
28 |
? $header->date : "" |
29 |
);
|
30 |
// handles fetch with uid and rfc header parsing
|
31 |
if ($msg['udate']==0 && isset($header->date)) { |
32 |
$msg['udate']=strtotime($header->date); |
33 |
}
|
34 |
$msg['rx_email']=''; |
35 |
$msg['rx_personal']=''; |
36 |
$msg['rx_mailbox']=''; |
37 |
$msg['rx_host']=''; |
38 |
if (isset($header->to)) { |
39 |
$to_arr = imap_rfc822_parse_adrlist($header->to,'gmail.com'); |
40 |
$to_info = $to_arr[0]; |
41 |
if (isset($to_info->mailbox) && isset($to_info->host)) { |
42 |
$msg['rx_email']=$to_info->mailbox.'@'.$to_info->host; |
43 |
}
|
44 |
if (isset($to_info->personal)) |
45 |
$msg['rx_personal']=$to_info->personal; |
46 |
if (isset($to_info->mailbox)) |
47 |
$msg['rx_mailbox']=$to_info->mailbox; |
48 |
if (isset($to_info->host)) |
49 |
$msg['rx_host']=$to_info->host; |
50 |
}
|
51 |
return $msg; |
52 |
}
|
53 |
}
|
Wir erstellen Datensätze für den Absender und den Nachrichtenumschlag in unserer Datenbank:
1 |
// skip any system messages
|
2 |
if ($msg['email']==$system_email) continue; |
3 |
// if udate is too old, skip msg
|
4 |
if (time()-$msg['udate']>$this->scan_seconds) continue; // skip msg |
5 |
// default action
|
6 |
$action = self::ACTION_MOVE_FILTERED; |
7 |
$isNew = $s->isNew($account_id,$msg["email"]); |
8 |
// look up sender, if new, create them
|
9 |
$sender_id = $s->add($user_id,$account_id,$msg["personal"], $msg["mailbox"], $msg["host"],0); |
10 |
$sender = Sender::model()->findByPk($sender_id); |
11 |
// create a message in db if needed
|
12 |
$message_id = $m->add($user_id,$account_id,0,$sender_id,$msg['message_id'],$msg['subject'],$msg['udate'],$msg['in_reply_to']); |
13 |
$message = Message::model()->findByPk($message_id); |
Wenn der Absender für uns neu ist (unbekannt), senden wir eine E-Mail mit einer Whitelist-Herausforderung (mehr über Whitelist-Herausforderungen im nächsten Abschnitt unten):
1 |
if ($isNew) { |
2 |
$this->challengeSender($user_id,$account_id,$sender,$message); |
3 |
}
|
Als Nächstes stellen wir fest, ob der Benutzer möglicherweise eine Nachricht aus einem anderen Ordner zurück in den Posteingang gezogen hat, um sie per Drag & Drop zu trainieren. In diesem Fall legen wir die Schulung für diesen Absender im Posteingang fest. Mit anderen Worten, beim nächsten Mal möchten wir nur Nachrichten von diesem Absender an den Posteingang weiterleiten:
1 |
if ($message['status'] == Message::STATUS_FILTERED || |
2 |
$message['status'] == Message::STATUS_REVIEW || |
3 |
($message['status'] == Message::STATUS_TRAINED && $message['folder_id'] <> $folder_id) || |
4 |
($message['status'] == Message::STATUS_ROUTED && $message['folder_id'] <> $folder_id)) |
5 |
{
|
6 |
// then it's a training
|
7 |
$action = self::ACTION_TRAIN_INBOX; |
8 |
} else if (($message['status'] == Message::STATUS_TRAINED || $message['status'] == Message::STATUS_ROUTED) && $message['folder_id'] == $folder_id) { |
9 |
// if trained already or routed to inbox already, skip it
|
10 |
$action = self::ACTION_SKIP; |
11 |
echo 'Trained previously, skip ';lb(); |
12 |
continue; |
13 |
}
|
Wenn nicht, bereiten wir uns darauf vor, die Nachricht zur weiteren Verarbeitung in den Filterordner zu verschieben. Erstens können wir Benachrichtigungen an das Telefon des Benutzers senden, wenn eine Absender- oder Keyword-Übereinstimmung für Benachrichtigungen vorliegt (und es keine ruhigen Stunden sind):
1 |
if ($action == self::ACTION_MOVE_FILTERED) { |
2 |
$cnt+=1; |
3 |
if ($sender->exclude_quiet_hours == Sender::EQH_YES or !$this->isQuietHours($user_id)) { |
4 |
// send smartphone notifications based on sender
|
5 |
if ($sender->alert==Sender::ALERT_YES) { |
6 |
$this->notify($sender,$message,Monitor::NOTIFY_SENDER); |
7 |
}
|
8 |
// send notifications based on keywords
|
9 |
if (AlertKeyword::model()->scan($msg)) { |
10 |
$this->notify($sender,$message,Monitor::NOTIFY_KEYWORD); |
11 |
}
|
12 |
}
|
13 |
// move imap msg to +Filtering
|
14 |
echo 'Moving to +Filtering';lb(); |
15 |
//$result = @imap_mail_move($this->stream,$msg['uid'],$this->path_filtering,CP_UID);
|
16 |
$result = $this->messageMoveHandler($msg['uid'],$this->path_filtering,false); |
17 |
if ($result) { |
18 |
echo 'moved<br />'; |
19 |
$m->setStatus($message_id,Message::STATUS_FILTERED); |
20 |
}
|
21 |
}
|
Wenn die Nachricht in den Posteingang gezogen wurde, aktualisieren wir unsere Trainingseinstellungen:
1 |
else if ($action == self::ACTION_TRAIN_INBOX) { |
2 |
// set sender folder_id to inbox
|
3 |
echo 'Train to Inbox';lb(); |
4 |
$m->setStatus($message_id,Message::STATUS_TRAINED); |
5 |
// only train sender when message is newer than last setting
|
6 |
if ($msg['udate']>=$sender['last_trained']) { |
7 |
$s->setFolder($sender_id,$folder_id); |
8 |
}
|
9 |
}
|
Die ProcessFiltering-Methode
Die sekundäre Verarbeitungsmethode heißt processFiltering
, auch in DaemonController.php
. Es erledigt die zeitaufwändigeren Aspekte des Verschiebens von Nachrichten in die entsprechenden Ordner:
1 |
public function actionIndex() |
2 |
{
|
3 |
// processes messages in @Filtering to appropriate folders
|
4 |
$r = new Remote(); |
5 |
$r->processFiltering(); |
6 |
// Record timestamp of cronjob for monitoring
|
7 |
$file = file_put_contents('./protected/runtime/cronstamp.txt',time(),FILE_USE_INCLUDE_PATH); |
8 |
}
|
Diese Methode öffnet Ihr E-Mail-Konto, um nach aktuellen Nachrichten zu suchen und Daten darüber zu sammeln. Es werden auch imap_search
, imap_fetch_overview
und parseHeader
verwendet:
1 |
$tstamp = time()-(7*24*60*60); // 7 days ago |
2 |
$recent_messages = @imap_search($this->stream, 'SINCE "'.date("j F Y",$tstamp).'"',SE_UID); |
3 |
if ($recent_messages===false) continue; // to do - continue into next account |
4 |
$result = imap_fetch_overview($this->stream, implode(',',array_slice($recent_messages,0,$message_limit)),FT_UID); |
5 |
foreach ($result as $item) { |
6 |
$cnt+=1; |
7 |
if (!$this->checkExecutionTime($time_start)) break; |
8 |
// get msg header and stream uid
|
9 |
$msg = $this->parseHeader($item); |
Die primäre Verarbeitungsschleife für jede Nachricht im Filterordner ist sehr detailliert. Zuerst betrachten wir die Empfängeradresse, da SE es Benutzern ermöglicht, Ordner nach Empfängeradresse zu trainieren, z. Nachrichten an die Domain happyvegetarian.com gehen in den vegetarischen Ordner:
1 |
// Set the default action to move to the review folder
|
2 |
$action = self::ACTION_MOVE_REVIEW; |
3 |
$destination_folder =0; |
4 |
// look up & create recipient
|
5 |
$recipient_id = $r->add($user_id,$account_id,$msg['rx_email'],0); |
6 |
$routeByRx = $this->routeByRecipient($recipient_id); |
7 |
if ($routeByRx!==false) { |
8 |
$action = $routeByRx->action; |
9 |
$destination_folder = $routeByRx->destination_folder; |
10 |
}
|
Dann suchen wir den Absender und erstellen einen neuen Datensatz in der Datenbank (falls erforderlich). Wenn für den Absender eine Schulung vorhanden ist, können wir den Zielordner festlegen:
1 |
// look up sender, if new, create them
|
2 |
$sender_id = $s->add($user_id,$account_id,$msg["personal"], $msg["mailbox"], $msg["host"],0); |
3 |
$sender = Sender::model()->findByPk($sender_id); |
4 |
// if sender destination known, route to folder
|
5 |
if ($destination_folder ==0 && $sender['folder_id'] > 0) { |
6 |
$action = self::ACTION_ROUTE_FOLDER; |
7 |
$destination_folder = $sender['folder_id']; |
8 |
}
|
9 |
Wenn sich ein nicht geschulter (neuer) Absender über eine Whitelist-Herausforderung verifiziert hat (die im nächsten Abschnitt erläutert wird), leiten wir diese Nachricht an den Posteingang weiter:
1 |
// whitelist verified senders go to inbox
|
2 |
if ($sender->is_verified==1 && $sender['folder_id'] ==0 && UserSetting::model()->useWhitelisting($user_id)) { |
3 |
// place message in inbox
|
4 |
$action = self::ACTION_ROUTE_FOLDER; |
5 |
$destination_folder = Folder::model()->lookup($account_id,$this->path_inbox); |
6 |
}
|
Anschließend erstellen wir einen Nachrichteneintrag in der Datenbank mit den Umschlaginformationen zu dieser Nachricht:
1 |
// create a message in db
|
2 |
$message = Message::model()->findByAttributes(array('message_id'=>$msg['message_id'])); |
3 |
if (!empty($message)) { |
4 |
// message exists already,
|
5 |
$message_id = $message->id; |
6 |
} else { |
7 |
$message_id = $m->add($user_id,$account_id,0,$sender_id,$msg['message_id'],$msg['subject'],$msg['udate'],$msg['in_reply_to']); |
8 |
}
|
Wenn es von einem unbekannten, nicht verifizierten Absender stammt, können wir die Nachricht in den Überprüfungsordner verschieben. Der Überprüfungsordner enthält alle Nachrichten von Absendern, die wir nicht erkennen.
Wenn die Nachricht von einem bekannten Absender stammt und wir ein Ziel vor Augen haben, können wir sie verschieben, solange es keine ruhigen Stunden sind (und nicht stören ist ausgeschaltet):
1 |
if ($recipient_id!==false) $m->setRecipient($message_id,$recipient_id); |
2 |
if ($action == self::ACTION_MOVE_REVIEW) { |
3 |
echo 'Moving to +Filtering/Review';lb(); |
4 |
//$result = @imap_mail_move($this->stream,$msg['uid'],$this->path_review,CP_UID);
|
5 |
$result = $this->messageMoveHandler($msg['uid'],$this->path_review,false); |
6 |
if ($result) { |
7 |
echo 'moved<br />'; |
8 |
$m->setStatus($message_id,Message::STATUS_REVIEW); |
9 |
}
|
10 |
} else if ($action == self::ACTION_ROUTE_FOLDER || $action == self::ACTION_ROUTE_FOLDER_BY_RX) { |
11 |
// lookup folder name by folder_id
|
12 |
$folder = Folder::model()->findByPk($destination_folder); |
13 |
// if inbox & quiet hours, don't route right now
|
14 |
if (strtolower($folder['name'])=='inbox' and $sender->exclude_quiet_hours == Sender::EQH_NO and $this->isQuietHours($user_id)) continue; |
15 |
echo 'Moving to '.$folder['name'];lb(); |
16 |
$mark_read = Folder::model()->isMarkRead($folder['mark_read']) || Sender::model()->isMarkRead($sender['mark_read']); |
17 |
//$result = @imap_mail_move($this->stream,$msg['uid'],$folder['name'],CP_UID);
|
18 |
$result = $this->messageMoveHandler($msg['uid'],$folder['name'],$mark_read); |
19 |
if ($result) { |
20 |
echo 'moved<br />'; |
21 |
$m->setStatus($message_id,Message::STATUS_ROUTED); |
22 |
$m->setFolder($message_id,$destination_folder); |
23 |
}
|
24 |
}
|
Während ruhiger Stunden werden Nachrichten hauptsächlich im Filterordner gespeichert.
Alle paar Stunden erstellt ein anderer Prozess den Nachrichtenauszug anhand der Nachrichtentabellendatensätze, um festzustellen, welche E-Mails kürzlich empfangen und gefiltert wurden und wie sie weitergeleitet wurden.
2. Implementieren einer Whitelist-Herausforderung für unbekannte Absender
Das Ziel der Whitelist-Herausforderung besteht darin, Nachrichten von einem unbekannten Absender, z. möglicherweise ein Marketing-Bot oder Spammer aus Ihrem Posteingang. SE legt E-Mails von unbekannten Absendern im Überprüfungsordner ab. Wenn Sie jedoch die Whitelist aktivieren, senden wir eine E-Mail mit einer Aufforderung, mit der der Absender überprüfen kann, ob er ein Mensch ist. Wenn sie antworten, verschieben wir die Nachricht in Ihren Posteingang. Wenn sich herausstellt, dass die E-Mail unerwünscht ist, können Sie die Nachricht aus dem Digest zappen oder in einen beliebigen Ordner ziehen, in den Sie sie trainieren möchten.
Der Benutzer kann die Whitelist in den folgenden Einstellungen ein und ausschalten:



Um die Whitelist zu implementieren, senden wir E-Mail-Herausforderungen, wenn E-Mails von einem neuen Absender eingehen:
1 |
if ($isNew) { |
2 |
$this->challengeSender($user_id,$account_id,$sender,$message); |
3 |
}
|
ChallengeSender
sendet einen codierten Link an den Benutzer, auf den er klicken kann. Wir haben auch einige Schutzmaßnahmen, um sicherzustellen, dass wir uns nicht in einer E-Mail-Schleife mit einer Abwesenheitsnachricht befinden:
1 |
public function challengeSender($user_id,$account_id,$sender,$message) { |
2 |
// whitelist email challenge
|
3 |
$yg = new Yiigun(); |
4 |
$ac = Account::model()->findByPk($account_id); |
5 |
if (!empty($ac['challenge_name'])) |
6 |
$from = $ac['challenge_name'].' <no-reply@'.$yg->mg_domain.'>'; |
7 |
else
|
8 |
$from = 'Filter <no-reply@'.$yg->mg_domain.'>'; |
9 |
$cred = Account::model()->getCredentials($ac->cred); |
10 |
$account_email = $cred[0]; |
11 |
unset($cred); |
12 |
// safety: checks no recent email
|
13 |
if ($sender->last_emailed>(time()-(48*60*60))) return false; |
14 |
if ($sender->isBot($sender['email'])) { |
15 |
// to do - can also set this person to bulk by default
|
16 |
return false; |
17 |
}
|
18 |
$link=Yii::app()->getBaseUrl(true)."/sender/verify/s/".$sender->id."/m/".$message->id.'/u/'.$message->udate; |
19 |
$subject = 'Please verify the message you sent to '.$account_email; |
20 |
$body="<p>Hi,<br /><br /> I'm trying to reduce unsolicited email. Could you please verify your email address by clicking the link below:<br /><a href=\"".$link.'">'.$link.'</a><br /><br />Verifying your email address will help speed your message into my inbox. Thanks for your assistance!</p>'; |
21 |
$yg->send_html_message($from, $sender['email'], $subject,$body); |
22 |
// update last_emailed
|
23 |
$sender->touchLastEmailed($sender->id); |
24 |
}
|
Wenn der Empfänger dann auf den codierten Link klickt, überprüfen wir ihn in der Datenbank. Der Sender Controller verarbeitet diese Anforderungen und überprüft ihre Gültigkeit:
1 |
public function actionVerify($s = 0, $m=0,$u=0) { |
2 |
// verify that secure msg url from digest is valid, log in user, show msg
|
3 |
$sender_id = $s; |
4 |
$message_id = $m; |
5 |
$udate = $u; |
6 |
$msg = Message::model()->findByPk($message_id); |
7 |
if (!empty($msg) && $msg->sender_id == $sender_id && $msg->udate == $udate) { |
8 |
$result = 'Thank you for your assistance. I\'ll respond to your email as soon as possible.'; |
9 |
$a = new Advanced(); |
10 |
$a->verifySender($msg->account_id,$sender_id); |
11 |
} else { |
12 |
$result = 'Sorry, we could not verify your email address.'; |
13 |
}
|
14 |
$this->render('verify',array( |
15 |
'result'=>$result, |
16 |
));
|
17 |
}
|
Dies weist unsere Verarbeitungsschleifen an, diese und zukünftige Nachrichten von diesem Absender in den Posteingang zu verschieben.
3. Melden unbeantworteter E-Mails
Manchmal ist es hilfreich, eine Zusammenfassung der Nachrichten anzuzeigen, auf die Sie gesendet, aber keine Antwort erhalten haben. Um diese zu identifizieren, überwacht Simplify Email Nachrichten, die gesendet wurden, aber keine Antwort erhalten haben.
Jede Nachricht, die wr erhalten, enthält eine eindeutige ID namens message_id (Teil der IMAP-Spezifikation). Es sieht oft so aus:
1 |
Message-Id: <CALe0OAaF3fb3d=gCq2Fs=Ex61Qp6FdbiA4Mvs6kTQ@mail.gmail.com> |
Wenn Nachrichten als Antwort auf andere Nachrichten gesendet werden, haben sie außerdem ein Feld in_reply_to
, das auf die ursprüngliche message_id
verweist.
Daher verwenden wir eine SQL-Abfrage, um alle empfangenen Nachrichten zu finden, für die keine entsprechende Antwortnachricht vorhanden ist, die auf ihre message_id
verweist. Dazu verwenden wir einen LEFT OUTER JOIN, bei dem es keine in_reply_to
id gibt:
1 |
public function getUnanswered($account_id,$mode=0, $range_days = 7) { |
2 |
if ($mode==0) |
3 |
$subject_compare = 'not'; |
4 |
else |
5 |
$subject_compare = ''; |
6 |
$query = Yii::app()->db->createCommand("SELECT fi_sent_message.id, fi_sent_message.recipient_id as 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 OUTER JOIN fi_message ON fi_message.in_reply_to = fi_sent_message.message_id WHERE fi_sent_message.account_id = ".$account_id." AND fi_message.in_reply_to is null and fi_sent_message.udate > ".(time()-(3600*24*$range_days))." and fi_sent_message.subject ".$subject_compare." like 'Re: %' ORDER BY fi_sent_message.udate DESC")->queryAll(); |
7 |
return $query; |
8 |
} |
Wir verwenden den $subject_compare
-Modus, um zwischen unseren gesendeten Nachrichten, die nicht beantwortet wurden, und unseren gesendeten Antworten auf einen Thread, der nicht beantwortet wurde, zu unterscheiden. Hier ist der unbeantwortete Nachrichtenbericht in Ihrem Konto:



SE bietet diese Informationen auch als optionalen Digest an, den so genannten unbeantworteten E-Mail-Digest. Sie können es jeden Tag, alle paar Tage oder jede Woche erhalten.
Wir verwendenauch eine ähnliche SQL-Tabelle mit Google Charts, um Berichte darüber bereitzustellen, wie häufig bestimmte Personen Ihnen E-Mails senden:



1 |
public function reportInbound($account_id,$range=30,$limit = 100) { |
2 |
$result= Yii::app()->db->createCommand('SELECT fi_sender.personal, fi_sender.email,count(sender_id) as cnt |
3 |
FROM fi_message LEFT JOIN fi_sender ON fi_sender.id =fi_message.sender_id WHERE fi_sender.account_id = :account_id AND fi_message.created_at > DATE_SUB( NOW() , INTERVAL :range DAY )
|
4 |
GROUP BY sender_id ORDER BY cnt desc LIMIT :limit ')->bindValue('range',$range)->bindValue('account_id',$account_id)->bindValue('limit',$limit)->queryAll(); |
5 |
return $result; |
6 |
}
|
Ich werde bald mehr über Google Charts for Tuts+ schreiben.
Nächste Schritte
Ich hoffe, Sie fanden Simplify Email faszinierend genug, um sich in der PHP IMAP-Programmierung zu versuchen. Es gibt so viele coole Funktionen, die Sie erstellen können, ohne dass die großen E-Mail-Anbieter etwas Neues tun müssen.
Wenn Sie Fragen oder Korrekturen haben, posten Sie diese bitte in den Kommentaren. Wenn Sie über meine zukünftigen Tuts+ -Tutorials und andere Serien auf dem Laufenden bleiben möchten, folgen Sie bitte @reifman oder besuchen Sie meine Autorenseite. Sie können mich auch hier kontaktieren.
verwandte Links
Hier sind einige zusätzliche Links, die Sie möglicherweise nützlich finden:
- E-Mail vereinfachen
- Einführung in Simplify Email (Video)
- Zwölf Google Mail-Ideen zur Revolutionierung von E-Mails (erneut)
- Berichterstattung über Simplify Email in BoingBoing hier und hier
- PHP IMAP Referenz
- Einführung in das Yii Framework (Tuts+)