Muss schnell los. Optimieren von IMAP-E-Mail-Inhaltsanforderungen

Hallo alle zusammen! In einem früheren Artikel habe ich darüber gesprochen, wie Sie den Inhalt einer Box im lokalen Cache schnell synchronisieren können. Hier möchte ich über die Funktionen zum Anfordern des Inhalts von Briefen sprechen und darüber, wie Inhalte am besten angefordert werden können, ohne Angst vor dem hohen Verkehrsverbrauch zu haben.

Bild

Erinnern wir uns schnell an das, was wir im letzten Artikel gelernt haben:

  • IMAP ist ein Stateful-Protokoll
  • Um den Inhalt des Posteingangs anzuzeigen, müssen Sie ihn zuerst mit dem Befehl SELECT auswählen
  • Um die Box, in der wir uns befinden, schnell zu synchronisieren, können Sie den Befehl NOOP verwenden
  • Um keine Nachrichten aus dem lokalen Speicher zu sortieren, um das bereits verbliebene Postfach zu aktualisieren, können Sie CONDSTORE und QRESYNC verwenden, sofern Ihr Server die Protokollerweiterungsdaten unterstützt

Genug!


Lassen Sie mich Sie an den Befehl erinnern, den Textkörper des Briefes anzufordern:

1 FETCH number (BODY[])

Dadurch wird eine Anforderung erstellt, den gesamten Textkörper und alle Anhänge abzurufen. Sehen Sie, wie lange es dauert, bis eine Nachricht in 42 Absätzen von Lorem Ipsum und mit einem Bild von 2 Megabyte angezeigt wird.

Fragen Sie zunächst nach der Größe der Nachricht auf dem Server. Dies geschieht durch den Befehl:

1 FETCH 18871 (RFC822.SIZE)

RFC822.SIZE gibt die Größe der Nachricht in Bytes zurück:

* 18871 FETCH (RFC822.SIZE 3937793)

Das heißt, unsere Nachricht nimmt fast 4 Megabyte ein.

Jetzt werden wir jedoch die Anfrage für den vollständigen Text des Briefes verwenden und einen Blick auf die Zeit werfen:

1 OK Fetch completed (0.007 + 3.265 secs).

3,3 Sekunden! Und dies ist nur eine Nachricht mit dem Anhang, und stellen Sie sich vor, dass dies die ganze Schachtel sein wird. Dann dauert es mehr als eine Minute, um mindestens die einundzwanzigsten herunterzuladen.

Sie müssen zugeben, dass das Geschäft eines Kunden, der im Jahr 2020 E-Mails nicht schneller als in einer Minute synchronisieren kann, schlecht ist. Aber was soll man machen?

Gib mir einmal einen Bissen


Wenn Sie RFC3501 in Abschnitt 6.5.4 rascheln , in dem die möglichen Parameter für den Befehl FETCH beschrieben werden, werden Sie eine interessante Anfrage bemerken:

BODY[<section>]<<partial>>

  • Abschnitt - welcher Teil des Briefes zu bekommen
  • teilweise - die Größe dieses Teils

Wie wird teilweise gebaut? Und es ist sehr einfach. Zuerst wird das Byte, von dem aus Sie mit dem Lesen beginnen müssen, durch den Punkt geschrieben, und dann, wie viele Bytes im Allgemeinen gelesen werden sollen:

BODY[<section>]<<0.1024>>

Hier fordern wir den Teil des Briefes von Null Byte bis 1024 an.

Okay, was ist ein Abschnitt? Zunächst werde ich über einen so nützlichen Parameter in einer FETCH-Abfrage wie BODYSTRUCTURE sprechen:

1 FETCH 18871 (BODYSTRUCTURE)

Dieser Parameter gibt, wie Sie wahrscheinlich aus der Signatur verstanden haben, die Struktur des Buchstabens in der in MIME-IMB beschriebenen Form zurück .

* 18871 FETCH (BODYSTRUCTURE ((("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 25604 337 NIL NIL NIL NIL)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 29593 390 NIL NIL NIL NIL) "alternative" ("boundary" "--=_Part_763_774309787.1586268692") NIL NIL NIL)("image" "jpeg" ("name" "IMG_20200217_000236.jpg") NIL NIL "base64" 3880726 NIL ("attachment" ("filename" "IMG_20200217_000236.jpg")) NIL NIL) "mixed" ("boundary" "--=_Part_210_297656922.1586268692") NIL NIL NIL))


Nur ein Blick auf diese Struktur, und Ihr Kopf dreht sich? Hab keine Angst, jetzt werden wir verstehen. Vergleichen Sie die öffnenden und schließenden Klammern.

(
BODYSTRUCTURE 
(
[1] (
[1.1] ("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 25604 337 NIL NIL NIL NIL)
[1.2] ("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 29593 390 NIL NIL NIL NIL) "alternative" ("boundary" "--=_Part_763_774309787.1586268692") NIL NIL NIL
)
[2] ("image" "jpeg" ("name" "IMG_20200217_000236.jpg") NIL NIL "base64" 3880726 NIL ("attachment" ("filename" "IMG_20200217_000236.jpg")) NIL NIL) "mixed" ("boundary" "--=_Part_210_297656922.1586268692") NIL NIL NIL
)
)


Sie werden vielleicht bemerken, dass ich Zahlen in die Nähe einiger Klammern setze. Dies ist ein Abschnitt.
Wie berechnet man sie? Die erste Klammer muss übersprungen werden, da sie lediglich die Antwort auf die Anfrage enthält. Dann muss jede öffnende Klammer gemäß der Regel nummeriert werden, da die Überschriften in den Dokumenten nummeriert sind:

  • Wir nummerieren jede öffnende Klammer unter Berücksichtigung des vorherigen Abschnitts
  • Wenn der Abschnitt verschachtelt ist, wird der aktuelle Abschnitt durch den Punkt zur vorherigen Nummer hinzugefügt
  • Wenn der Abschnitt nicht verschachtelt ist, erhöhen Sie seine Anzahl um eins


In diesem Fall gibt es beispielsweise im ersten Teil, der mit „Alternative“ endet (dh dies ist der Teil des mehrteiligen / alternativen Buchstabens, in dem wir frei wählen können, welche der Teile für den Benutzer angezeigt werden sollen), zwei Abschnitte, die durch einen Punkt nummeriert sind. Ich habe einen Server getroffen, auf dem möglicherweise drei Ebenen verschachtelt sind (z. B. [1.1.1], [1.1.2] usw.).
Lassen Sie uns den Teil [1.1] analysieren, in dem die Struktur all dieser Dinge im MIME-IMB- Dokument betrachtet wird . Demnach ist der Content-Type-Header der erste. Es enthält:

  • MIME-Typ, hier ist es Text / Plain
  • Codierung (Zeichensatz = utf8)


Das Folgende sind zwei Parameter, die als NIL geschrieben werden. Ehrlich gesagt habe ich nicht verstanden, was es war, aber bisher habe ich es nicht gebraucht, also werde ich es vermissen. Ich entschuldige mich für diese Frivolität.
Als nächstes folgt der Content-Transfer-Encoding-Header, der den Codierungsmechanismus beschreibt. Hier wird er in Anführungszeichen gedruckt. 
Die folgenden zwei Zahlen beschreiben die Größe des Teils in Bytes und die Anzahl der Zeilen, falls möglich. Mit ihrer Hilfe können wir berechnen, wie viele Bytes benötigt werden, um eine bestimmte Anzahl von Zeilen anzuzeigen.
Die folgenden Zeilen, die nicht in diesem Teil enthalten sind:

  • Inhalts-ID, die in der Inline des Briefes verwendet wird
  • Inhaltsbeschreibung, eine Zeile, die beschreibt, was dieser Teil ist


Für die beiden anderen Parameter konnte ich keine eindeutige Antwort finden, was es ist, aber einer dieser Parameter kann MD5-Teile enthalten, was manchmal nützlich sein kann.
Für Teil [2] ist alles gleich, außer dass es sich um ein Bild, einen Anhang mit einem Namen und eine Base64-Codierung handelt. Wenn immer noch nicht ganz klar ist, was hier passiert, ist auf dieser Website genau beschrieben, wie der Abschnitt berechnet wird.

Was gibt es? Und die Tatsache, dass wir zum Zeitpunkt der Anzeige des Briefes bereits nur den oberen Teil des Inhalts anfordern und die Anhänge erst laden können, wenn der Benutzer selbst die Nachricht eingibt und auf die Schaltfläche "Herunterladen" klickt. Alle Informationen zum Anzeigen von Anhängen erhalten Sie in BODYSCTRUCTURE, sodass Name, Format und Größe angezeigt werden können, ohne den Anhang selbst zu laden. 

Lass uns weiter üben. Wir werden um ein Kilobyte Nachrichteninhalt ohne Anhänge bitten, nur um zu wissen, was sie uns gesendet haben.

1 fetch 18871 (body[1.1]<0.1024>)
* 18871 FETCH (BODY[1.1]<0> {1024}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus consecte=
tur enim in nisi venenatis, id varius tellus viverra. Praesent et enim te=
llus. Nunc vestibulum diam tortor, id posuere turpis tempor luctus. Vivam=
us molestie non nunc nec placerat. Cras finibus ut erat et tristique. Cur=
abitur vitae commodo risus. Etiam sed scelerisque erat. Quisque cursus bl=
andit finibus. Nullam ac lectus accumsan, molestie quam non, mollis urna.=
 Nulla at arcu in libero condimentum mollis ut non velit. Vestibulum sed =
risus et magna congue iaculis. Vestibulum nec interdum elit, ut commodo m=
auris. Nulla ipsum leo, vestibulum nec ligula non, elementum ullamcorper =
risus. Nunc et malesuada sem, id venenatis massa. Integer dolor ante, max=
imus in eleifend nec, ultricies ut risus. Mauris posuere eget tortor at p=
orttitor.=0AIn porta elementum ornare. Suspendisse aliquam, tortor sed al=
iquam bibendum, nulla ante rhoncus elit, placerat accumsan augue nibh non=
 est. Duis finibus vel tortor finibu)
1 OK Fetch completed (0.073 + 0.000 + 0.072 secs).


Etwa 100 Millisekunden und wir sehen bereits einen Teil des Inhalts des Briefes! Dies ist nur ein hervorragendes Ergebnis, da wir zuvor fast 4 Sekunden gebraucht haben, um den Inhalt eines Briefes herunterzuladen. Dann können Sie einfach den gesamten Inhalt des Briefes in den Hintergrund-Stream laden. Von außen sieht es so aus, als würden die Buchstaben sofort geladen. Alles, was erforderlich war, war, die Struktur des Briefes zu betrachten und nur das herunterzuladen, was für eine schnelle Anzeige erforderlich ist. 
Nur einen Moment. Durch diese Anforderung wird die Nachricht auf dem Server als gelesen angezeigt. Sie können dies jedoch beheben, indem Sie der Textanforderung nur PEEK hinzufügen

1 fetch 18871 (BODY.PEEK[1.1]<0.1024>)
* 18871 FETCH (BODY[1.1]<0> {1024}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus consecte=
tur enim in nisi venenatis, id varius tellus viverra. Praesent et enim te=
llus. Nunc vestibulum diam tortor, id posuere turpis tempor luctus. Vivam=
us molestie non nunc nec placerat. Cras finibus ut erat et tristique. Cur=
abitur vitae commodo risus. Etiam sed scelerisque erat. Quisque cursus bl=
andit finibus. Nullam ac lectus accumsan, molestie quam non, mollis urna.=
 Nulla at arcu in libero condimentum mollis ut non velit. Vestibulum sed =
risus et magna congue iaculis. Vestibulum nec interdum elit, ut commodo m=
auris. Nulla ipsum leo, vestibulum nec ligula non, elementum ullamcorper =
risus. Nunc et malesuada sem, id venenatis massa. Integer dolor ante, max=
imus in eleifend nec, ultricies ut risus. Mauris posuere eget tortor at p=
orttitor.=0AIn porta elementum ornare. Suspendisse aliquam, tortor sed al=
iquam bibendum, nulla ante rhoncus elit, placerat accumsan augue nibh non=
 est. Duis finibus vel tortor finibu)
1 OK Fetch completed (0.001 + 0.000 secs).


Und voila! Der Brief bleibt ungelesen und ein Teil des Inhalts, den wir erhalten haben.
Alles wird noch einfacher, wenn die PREVIEW- Anforderungsfunktion auf Ihrem Server implementiert ist. 

1 fetch 18871 (PREVIEW)
* 18871 FETCH (PREVIEW (FUZZY "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus consectetur enim in nisi venenatis, id varius tellus viverra. Praesent et enim tellus. Nunc vestibulum diam tortor, id posuere turpis t"))
1 OK Fetch completed (0.001 + 0.000 secs).


Hier verbringen wir überhaupt keine Zeit damit, die Struktur abzufragen, und wir erhalten sofort die Nachrichtenvorschau. Vergessen Sie jedoch nicht, dass die Abfragestruktur nützlich ist, um Anhänge zu definieren, damit sie nicht in den Leerlauf geladen werden.

Warten


Fast jeder Mail-Client implementiert die Schaltfläche "Aktualisieren", wenn der Benutzer gerade neue Briefe erhalten möchte. Aber irgendwie ist das für unsere Zeit nicht cool, da es Benachrichtigungen sowohl auf Geräten als auch in Browsern gibt. Was sagt IMAP dazu? Und er sagt LEERLAUF . Dieser Vorgang hält die Verbindung zum Ordner aufrecht und benachrichtigt Sie über Änderungen am Ordner. Bitte beachten Sie nicht die Mailbox, sondern die Ordner. Dazu muss der Server die IDLE-Funktion implementieren. 

Wählen Sie zunächst den Ordner aus, für den der Server Warnungen senden soll, und aktivieren Sie dann IDLE

1 SELECT Inbox
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded $MDNSent)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded $MDNSent \*)] Flags permitted.
* 18872 EXISTS
* 0 RECENT
* OK [UNSEEN 18685] First unseen.
* OK [UIDVALIDITY 1532079879] UIDs valid
* OK [UIDNEXT 20155] Predicted next UID
* OK [HIGHESTMODSEQ 26338] Highest
1 OK [READ-WRITE] Select completed (0.002 + 0.000 + 0.001 secs).
1 IDLE
+ idling


Die Antwort "+ Leerlauf" benachrichtigt über die Aufnahme des Leerlaufs in den Ordner. Was passiert, wenn ein neuer Brief eintrifft?

* 18873 EXISTS
* 1 RECENT


Ich schickte mir den gleichen Brief, und Idle teilte mir mit, dass ich den Brief 18873 anfordern sollte, dass sich 18873 Briefe im Ordner befanden und dass ein Brief gerade eingetroffen war.
Als nächstes werde ich diesen Brief in einem anderen Zusammenhang anfordern, wir interessieren uns für den Brief mit der Antwort EXISTS.

1 fetch 18873 (BODY.PEEK[1.1]<0.1024>)
* 18873 FETCH (BODY[1.1]<0> {1024}
---- Original Message ---- Tue, Apr 7, 2020, 17:11=0ASubject=
: Lorem Ipsum=0A  Lorem ipsum dolor sit amet, consectetur adipiscing elit=
. Vivamus consectetur enim in nisi venenatis, id varius tellus viverra. P=
raesent et enim tellus. Nunc vestibulum diam tortor, id posuere turpis te=
mpor luctus. Vivamus molestie non nunc nec placerat. Cras finibus ut erat=


Es ist sehr wichtig zu verstehen. IDLE erfordert eine separate Verbindung, sodass Sie in derselben Sitzung keine Änderungen empfangen und Nachrichten anfordern können.
Was kann IDLE sonst noch tun? Er kann über gelöschte Briefe und Briefe, deren Flaggen sich geändert haben, benachrichtigen. Schauen wir uns den Buchstaben als Beispiel an, setzen Sie das Flag "/ Seen" darauf und löschen Sie den Buchstaben.

* 18873 FETCH (FLAGS (\Seen \Recent))
* OK Still here
* OK Still here
* 18873 EXPUNGE
* 18871 EXPUNGE
* 0 RECENT


Ich habe das Gespräch gelöscht (18873, 18871) und mir einen anderen Brief angesehen (FETCH-Antwort). Warum wurde dieser Brief 18871? Weil IMAP die Buchstabennummer nachzählt, wenn sich etwas geändert hat. Da es das oberste wurde, änderte sich auch seine Nummer. 
Mit IDLE können wir den Status der Box schnell synchronisieren, aber es ist unangenehm, dass eine separate Verbindung erforderlich ist. Könnte es besser sein? Deshalb bin ich hier.

Schrei, wie geht es dir?


Was ist, wenn ich Ihnen sage, dass es eine Funktion gibt, mit der Sie Benachrichtigungen vom Server in derselben Verbindung empfangen können und die sogar speziell für Postfächer konfiguriert sind und nicht einmal eine. Es klingt wie ein Märchen, aber nicht verrückt werden, das ist eine echte Fähigkeit NOTIFY . Er weiß viel zum Beispiel:

  • Konfigurieren Sie bestimmte Ordner, von denen wir Benachrichtigungen erwarten
  • Änderungen des Ordnerstatus anhören (Briefe lesen, neue Briefe)
  • Legen Sie das Benachrichtigungsformat fest, dh das, was beim Ändern des Ordners angezeigt werden soll
  • Hören Sie sich Änderungen am Ordnernamen an
  • Hören Sie sich Änderungen an Ordner-Metadaten an


Schauen wir uns ein Beispiel an, wie wir Änderungen des Ordnerstatus abhören können

1 notify set (inboxes (MessageNew FlagChange MessageExpunge))
1 OK NOTIFY completed (0.001 + 0.000 secs).


Jetzt sendet uns der Server Benachrichtigungen mit Ordnerstatus, zum Beispiel füge ich ein paar Nachrichten zu verschiedenen Ordnern hinzu

* STATUS INBOX/Ozon (MESSAGES 312 UIDNEXT 321 UNSEEN 48)
* STATUS "INBOX/Company News" (MESSAGES 178 UIDNEXT 179 UNSEEN 1)
* STATUS "INBOX/Company News" (MESSAGES 177 UIDNEXT 179 UNSEEN 0)


Ich werde den Befehl analysieren:
Zuerst kommt der Befehl NOTIFY SET. Als nächstes wählen wir in Klammern aus, welche Ordner wir anhören möchten:

  • Posteingänge - für alle Ordner, die Sie auswählen können
  • Persönlich - Ordner, die sich im Namespace des Benutzers befinden
  • Abonniert - Ordner, die der Benutzer abonniert hat
  • Teilbaum - Teilbaum des anzugebenden Ordners
  • Postfächer - Hier können Sie die Ordner auflisten, die Sie anhören möchten.
  • Ausgewählt - Warnung nur für ausgewählte Ordner


Und die Parameter, die für den Alarmfilter verantwortlich sind:

  • MessageNew - wenn eine neue Nachricht eintrifft
  • FlagChange - wenn sich das Flag geändert hat
  • MessageExpunge - wenn die Nachricht gelöscht oder verschoben wurde


Mit einem solchen Befehl können wir jedoch nicht die Parameter einer neuen, geänderten oder gelöschten Nachricht empfangen. Wählen Sie dazu den Parameter Ausgewählt aus und geben Sie an, was genau zurückgegeben werden soll. Wir können eine weitere Warnung hinzufügen, ohne die vorherige zu löschen.

1 notify set status (selected (MessageNew (uid preview) MessageExpunge))


Hier in MessageNew geben wir die Parameter an, die die Benachrichtigung zurückgeben soll. Ich werde Posteingang wählen und wieder lorem ipsum für mich werfen.

* 18868 FETCH (UID 20157 PREVIEW (FUZZY "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus consectetur enim in nisi venenatis, id varius tellus viverra. Praesent et enim tellus. Nunc vestibulum diam tortor, id posuere turpis t"))


Wie gefällt es Ihnen? Für den Leerlauf müssen zwei Verbindungen bestehen bleiben, von denen eine auch Nachrichten anfordert, die der Leerlauf an uns zurückgegeben hat. Sofort bringen sie uns alles auf einen Silbertablett. 
Und so können wir Änderungen an Ordnernamen anhören

1 notify set (inboxes (MailboxName))


Benennen Sie einen Ordner um und sehen Sie das Ergebnis.

* LIST () "/" 1111 ("OLDNAME" (aaaa))


Und jetzt wissen wir, dass es einen Ordner "aaaa" gab, der zu "1111" wurde.
Jetzt können Sie den Wechsel der Flags und das Entfernen von Nachrichten abhören. Verwenden Sie dazu den Parameter FlagChange

1 notify set (selected (MessageNew (uid) FlagChange MessageExpunge))


Und wenn Sie die Nachrichtenflags ändern und löschen, erhalten wir

* 18865 EXPUNGE
* 18864 FETCH (FLAGS ())
* 18864 FETCH (FLAGS (\Answered))


Was weiter


All diese Funktionen helfen dem E-Mail-Client, für den Benutzer so schnell und bequem wie möglich zu arbeiten. IDLE und NOTIFY benachrichtigen den Benutzer über Änderungen in Ordnern. Wenn Sie einen Teil des Briefes anfordern, wird das Laden beschleunigt. 
Im letzten Artikel möchte ich über den Suchmechanismus in IMAP sprechen und darüber, wie er beschleunigt und die Belastung des Netzwerks verringert werden kann. Vielen Dank für das Lesen bis zum Ende. 

All Articles