IMAPClient und die Verflachung der BODYSTRUCTURE
Die Reduzierung der BODYSTRUCTURE setzt voraus, dass Sie mit der Lektüre des RFC3501 beginnen.
Anwendungsentwickler wollen bewährte Lösungen verwenden, um eine Anwendung zu erstellen. Oftmals funktioniert dies, aber beim IMAPClient -Paket fehlt eine Reihe von Dingen.
Die ganze Idee von IMAP ist es, nur das zu bekommen, was Sie anfordern. Angenommen, Sie haben eine E-Mail mit vielen Anhängen, möchten aber nur einen davon anzeigen oder herunterladen. Dazu benötigen Sie die 'body_number' dieses Anhangs und dann FETCH diesen Teil.
Im Internet sieht man Leute, die die ganze Nachricht herunterladen, aber das ist nicht der richtige Weg, dies zu tun! Hier stelle ich eine Lösung vor, um die body_numbers aller Teile einer E-Mail-Nachricht zu erhalten.
Abflachen des BODYSTRUCTURE
Ich habe mich damit selbst schwer getan und als Einstieg einen Code verwendet, den ich im Internet gefunden habe, der aber nur von begrenztem Nutzen war. Es ist an der Zeit, den RFC3501 zu lesen, siehe Links unten. Eine IMAP -E-Mail-Nachricht besteht nicht nur aus Anhängen wie images und PDF -Dateien, sondern die Anhänge können auch selbst Nachrichten sein, was bedeutet, dass unser Code eine Rekursion verwenden muss.
Was ich möchte, ist eine Liste von body_numbers , die verwendet werden kann, um FETCH den oder die gewünschten Teile zu finden. Wir können diesen Vorgang als "Flatten the BODYSTRUCTURE" bezeichnen, weil wir von Rekursionen zu einer Liste übergehen. Während dieses Prozesses erzeugen wir die body_numbers.
MULTIPART/ALTERNATIVE, MULTIPART/MIXED, MULTIPART/RELATED, ...
E-Mail-Nachrichten sind meist aus Elementen aufgebaut, die miteinander in Beziehung stehen. Es gibt verschiedene Arten von Beziehungen, zum Beispiel:
- ALTERNATIVE: die alternativen Teile haben den gleichen Inhalt, so dass der Mail-Client auswählen kann, welcher angezeigt werden soll
- RELATED: Die Teile sollen zusammen und nicht alternativ dargestellt werden. Folglich werden sie kombiniert. z.B. Inline-Image
- MIXED: die Teile enthalten unterschiedliche Informationen und sollen nicht zusammen dargestellt werden.
Das Dokument 'IMAP BODYSTRUCTURE: formatted examples' gibt eine gute Einführung, siehe Links unten.
Hier ist ein Beispiel für eine ALTERNATIVE -Beziehung. Die von IMAPClient zurückgegebene BODYSTRUCTURE ist:
(
[
(b'text', b'plain', (b'charset', b'iso-8859-1'), None, None, b'quoted-printable', 426, 15, None, None, None, None),
(b'text', b'html', (b'charset', b'iso-8859-1'), None, None, b'quoted-printable', 1085, 36, None, None, None, None)
],
b'alternative',
(b'boundary', b'_000_CWXP265MB4244C3FA1F3563A988AAE2CABBDF9CWXP265MB4244GBRP_'),
None,
(b'en-US',),
None
)
IMAPClient gibt uns eine Liste von ALTERNATIVE Elementen. Wir können wählen, ob wir den reinen Text oder den Teil HTML anzeigen wollen. Die abgeflachten body_parts sind, erste Zahl ist die body_number:
1 - ALTERNATIVE : TEXT, text/plain, iso-8859-1
2 - ALTERNATIVE : TEXT, text/html, iso-8859-1
Hier ist das gleiche Beispiel mit einem hinzugefügten PDF -Anhang:
(
[
(
[
(b'text', b'plain', (b'charset', b'UTF-8'), None, None, b'8bit', 1268, 25, None, (b'inline', None), None, None),
(b'text', b'html', (b'charset', b'UTF-8'), None, None, b'8bit', 10887, 115, None, (b'inline', None), None, None)
],
b'alternative',
(b'boundary', b'alt-60e413d9174229.65052373'),
None,
None,
None
),
(b'application', b'pdf', (b'name', b'summary.pdf'), None, None, b'base64', 187354, None,
(b'attachment', (b'filename', b'summary.pdf')), None, None)
],
b'mixed',
(b'boundary', b'multipart-60e413d9174190.84932644'),
None,
None,
None
)
Die abgeflachten body_parts sind, erste Nummer ist die body_number:
1.1 - ALTERNATIVE : TEXT, text/plain, utf-8
1.2 - ALTERNATIVE : TEXT, text/html, utf-8
2 - MIXED : NON_MULTIPART-ATTACHMENT, application/pdf, summary.pdf
Woher kommen die body_numbers ?
Wir erhalten die body_numbers nicht vom IMAP -Server. Stattdessen erhalten wir die BODYSTRUCTURE vom IMAP -Server und müssen daraus die body_numbers erzeugen. In den obigen Beispielen ist dies nicht schwierig. Aber bei angehängten Nachrichten wird es komplizierter.
Der Aufbau des BODYSTRUCTURE
Um die BODYSTRUCTURE zu verstehen, habe ich etwas Text aus der RFC3501 kopiert:
Die grundlegenden Felder einer nicht mehrteiligen body part sind in der folgenden Reihenfolge:
- body type
Eine Zeichenkette, die den Namen des Medientyps des Inhalts angibt, wie in [MIME-IMB] definiert. -
body subtype
Eine Zeichenkette, die den Namen des Inhaltssubtyps gemäß der Definition in [MIME-IMB] angibt. -
body parameter parenthesized list
Eine in Klammern gesetzte Liste von Attribut/Wert-Paaren [z. B. ("foo" "bar" "baz" "rag"), wobei "bar" der Wert von "foo" und "rag" der Wert von "baz" ist], wie in [MIME-IMB] definiert. -
body id
Eine Zeichenkette, die die Inhalts-ID gemäß der Definition in [MIME-IMB] angibt. -
body description
Eine Zeichenkette, die den Inhalt angibt, wie in [MIME-IMB] definiert. -
body encoding
Eine Zeichenkette, die die Kodierung der Inhaltsübertragung gemäß der Definition in [MIME-IMB] angibt. -
body size
Eine Zahl, die die Größe des Bodys in Oktetten angibt. Beachten Sie, dass diese Größe die Größe in seiner Übertragungskodierung ist und nicht die resultierende Größe nach einer Dekodierung.
Ein body type des Typs MESSAGE und des Subtyps RFC822 enthält unmittelbar nach den Basisfeldern die Hüllstruktur, die Körperstruktur und die Größe der gekapselten Nachricht in Textzeilen.
Eine body type vom Typ TEXT enthält unmittelbar nach den Basisfeldern die Größe des Bodys in Textzeilen. Es ist zu beachten, dass diese Größe die Größe in der Inhaltsübertragungskodierung ist und nicht die resultierende Größe nach einer eventuellen Dekodierung.
Die Erweiterungsdaten folgen auf die Basisfelder und die oben aufgeführten typspezifischen Felder. Erweiterungsdaten werden nie mit dem BODY-Fetch zurückgegeben, können aber mit einem BODYSTRUCTURE -Fetch zurückgegeben werden. Wenn Erweiterungsdaten vorhanden sind, MÜSSEN sie in der festgelegten Reihenfolge vorliegen.
Beachten Sie, dass der body type vom Typ MESSAGE und Subtyp RFC822 eine Rekursion einführt. Wenn wir darauf stoßen, verarbeiten wir diese Nachricht als neue Nachricht, extrahieren body_number's, usw. Und diese Nachricht kann wiederum eine oder mehrere andere Nachrichten enthalten.
Gemäß RFC3501 enthält jede Nachricht eine Envelope-Struktur und eine Body-Struktur. Die Body-Struktur der Nachricht ist die neue Body-Struktur, die wir verarbeiten müssen.
Beispiel für verschachtelte Nachrichten
Hier ist ein Beispiel für eine Nachricht, die eine andere Nachricht enthält, die wiederum eine andere Nachricht mit einer Anlage enthält. Die BODYSTRUCTURE , die von IMAPClient zurückgegeben wird, ist:
(
[
(b'text', b'plain', (b'charset', b'utf-8'), None, None, b'7bit', 35, 7, None, None, None, None),
(b'message', b'rfc822', (b'name', b'Re: My message.eml'), None, None, b'7bit', 10034116,
(
b'Sun, 19 Sep 2021 10:04:43 +0200',
b'Re: My message',
((b'Bob Smith', None, b'bobsmith', b'example.com'),),
((b'Bob Smith', None, b'bobsmith', b'example.com'),),
((b'Bob Smith', None, b'bobsmith', b'example.com'),),
((b'richardroe@example.org', None, b'richardroe', b'example.org'),),
None,
None,
None,
b'<8b678e28-d03a-2bdd-2930-12470235ef9a@example.com>'
),
(
(b'text', b'plain', (b'charset', b'utf-8'), None, None, b'7bit', 46, 7, None, None, None, None),
(b'message', b'rfc822', (b'name', b'Fw: Some email two.eml'), None, None, b'7bit', 10029135,
(
b'Sat, 18 Sep 2021 18:35:47 +0200',
b'Fw: Some email two',
((b'John Doe', None, b'johndoe', b'example.org'),),
((b'John Doe', None, b'johndoe', b'example.org'),),
((b'John Doe', None, b'johndoe', b'example.org'),),
((None, None, b'richardroe', b'example.org'),),
None,
None,
None,
b'<a7dfbf41-1a26-4316-b8b5-1753fc17cd54-1631982946791@3c-example.org>'),
(
(b'text', b'html', (b'charset', b'UTF-8'), None, None, b'7bit', 5053, 89, None, None, None, None),
(b'application', b'pdf', (b'name', b'YZ345.pdf'), None, None, b'base64', 187354, None,
(b'attachment', (b'filename', b'YZ345.pdf')), None, None),
b'mixed',
(b'boundary', b'abmob-49888c7b-3a09-4d10-b119-df9366de9f4c'),
None,
None,
None
),
128656,
None,
(b'attachment', (b'filename', b'Fw: Some email two.eml')),
None,
None
),
b'mixed',
(b'boundary', b'------------3F95A42110AABF9E24EC86EB'),
None,
(b'en-US',),
None
),
128759,
None,
(b'attachment', (b'filename', b'Re: My message.eml')), None, None
)
],
b'mixed',
(b'boundary', b'------------7323DBBF0E22BDA4B95E42D1'),
None,
(b'en-US',),
None
)
Die abgeflachten body_parts sind, erste Zahl ist die body_number:
1 - MIXED : TEXT, text/plain, utf-8
2 - MIXED : MESSAGE_RFC822, message/rfc822, Re: My message.eml
2.1 - MIXED : TEXT, text/plain, utf-8
2.2 - MIXED : MESSAGE_RFC822, message/rfc822, Fw: Some email two.eml
2.2.1 - MIXED : TEXT, text/html, utf-8
2.2.2 - MIXED : NON_MULTIPART-ATTACHMENT, application/pdf, YZ345.pdf
Fixierung der BODYSTRUCTURE der verschachtelten Meldungen
Wenn Sie sich das obige Beispiel für verschachtelte Nachrichten ansehen, werden Sie feststellen, dass verschachtelte Nachrichten keine Listen enthalten, wie die Nachricht der obersten Ebene. Ich halte dies für einen Fehler, aber vielleicht ist es auch eine Designentscheidung.
Wie auch immer, IMAPClient enthält eine Klasse, die wir verwenden können, um die verschachtelte Nachricht BODYSTRUCTURE in eine Nachricht der obersten Ebene BODYSTRUCTURE zu konvertieren.
body_data = BodyData()
body_structure = body_data.create(nested_message_body_structure_part)
Die geschachtelte Nachricht BODYSTRUCTURE enthält nun Listen und kann auf die gleiche Weise verarbeitet werden wie die oberste Ebene BODYSTRUCTURE.
Die Klasse BodyStructurePart und die Teiltypen
Beim Flattening wird eine Liste von BodyStructurePart-Objekten erstellt. Eine BodyStructurePart-Klasse enthält alle Informationen für die weitere Verarbeitung. Sie muss mindestens die folgenden Informationen enthalten:
- body_number: die body_number
- body_type: ALTERNATIVE, MIXED, usw.
- body_part: der eigentliche Teil des BODYSTRUCTURE
Darüber hinaus habe ich Attribute hinzugefügt:
- part_type
- part_subtype
- content_type
Ein part_type kann sein, siehe auch RFC3501 oben:
- MESSAGE_RFC822
- TEXT
- NON_MULTIPART
Ein part_subtype, verwendet mit part_type = NON_MULTIPART, kann sein:
- ATTACHMENT
- INLINE
- OTHER
Der BODYSTRUCTURE Parser-Code
Und schließlich ist hier der Parser-Code. Er enthält drei Klassen:
- IMAPBodyStructurePartUtils
- IMAPBodyStructurePart
- IMAPBodyStructureParser
Die Klasse IMAPBodyStructureParser hat eine Parse-Methode, die mit der von IMAPClient zurückgegebenen BODYSTRUCTURE aufgerufen wird. Diese Methode gibt eine Liste von IMAPBodyStructurePart -Objekten zurück, die in unserem Code verwendet werden können.
Ich habe den Code und die Beispiele in einer einzigen Datei zusammengefasst, falls Sie es ausprobieren möchten:
import sys
from imapclient import IMAPClient
from imapclient.response_types import BodyData
class IMAPBodyStructurePartUtils:
@classmethod
def __decode(cls, s):
try:
s = s.decode()
except Exception as e:
pass
return s
@classmethod
def get_part_type_and_part_subtype(cls, body_part):
part_type = None
part_subtype = None
try:
if body_part[0] == b'message' and body_part[1] == b'rfc822':
part_type = 'MESSAGE_RFC822'
elif body_part[0] == b'text':
part_type = 'TEXT'
else:
part_type = 'NON_MULTIPART'
except:
pass
if part_type == 'NON_MULTIPART':
try:
if body_part[8][0] == b'attachment':
part_subtype = 'ATTACHMENT'
elif body_part[8][0] == b'inline':
part_subtype = 'INLINE'
else:
part_subtype = 'OTHER'
except Exception as e:
pass
return part_type, part_subtype
@classmethod
def get_content_type(cls, body_part):
try:
ctype = cls.__decode(body_part[0])
csubtype = cls.__decode(body_part[1])
return ctype.lower() + '/' + csubtype.lower()
except Exception as e:
pass
return None
@classmethod
def __get_charset_or_name(cls, charset_or_name, body_part):
try:
for a in range(0, len(body_part[2]), 2):
key = body_part[2][a].lower()
val = body_part[2][a + 1]
if key == charset_or_name:
if charset_or_name == b'charset':
return cls.__decode(val).lower()
return cls.__decode(val)
except Exception as e:
pass
return None
@classmethod
def get_charset(cls, body_part):
return cls.__get_charset_or_name(b'charset', body_part)
@classmethod
def get_name(cls, body_part):
return cls.__get_charset_or_name(b'name', body_part)
@classmethod
def get_filename(cls, body_part):
try:
sub_body_part = body_part[8][1]
for i in range(0, len(sub_body_part), 2):
key = sub_body_part[i]
val = sub_body_part[i + 1]
if key == b'filename':
return cls.__decode(val)
except:
pass
return None
class IMAPBodyStructurePart:
def __init__(
self,
body_number=None,
body_type=None,
body_part=None,
):
self.body_number = body_number
self.body_type = body_type
self.body_part = body_part
self.part_type, self.part_subtype = IMAPBodyStructurePartUtils.get_part_type_and_part_subtype(self.body_part)
self.content_type = IMAPBodyStructurePartUtils.get_content_type(self.body_part)
self.name = IMAPBodyStructurePartUtils.get_name(self.body_part)
self.charset = IMAPBodyStructurePartUtils.get_charset(self.body_part)
self.filename = IMAPBodyStructurePartUtils.get_filename(self.body_part)
def __str__(self):
if self.body_type is None:
self.body_type = ''
if self.part_type == 'MESSAGE_RFC822':
return '{:8} - {:12}: {}, {}, {}'.format(self.body_number, self.body_type, self.part_type, self.content_type, self.name)
elif self.part_type == 'TEXT':
return '{:8} - {:12}: {}, {}, {}'.format(self.body_number, self.body_type, self.part_type, self.content_type, self.charset)
return '{:8} - {:12}: {}-{}, {}, {}'.format(self.body_number, self.body_type, self.part_type, self.part_subtype, self.content_type, self.filename)
class IMAPBodyStructureParser:
def __init__(
self,
dbg=False,
):
pass
@classmethod
def __is_multipart(cls, part):
return isinstance(part[0], list)
@classmethod
def __get_body_type(cls, part):
# body_type (ALTERNATIVE, MIXED, ...) is first item after list
body_type = None
if len(part) > 1:
body_type = part[1]
if body_type is not None:
try:
body_type = body_type.decode()
except Exception as e:
pass
if body_type is not None:
body_type = body_type.upper()
return body_type
@classmethod
def __add_body_part(cls, body_parts, body_number, body_type, part):
body_parts.append(IMAPBodyStructurePart(
body_number=body_number,
body_type=body_type,
body_part=part,
))
@classmethod
def parse(cls, part, body_number='', body_type=None):
return cls.__recursive_parse(body_parts=[], part=part, body_number=body_number, body_type=body_type)
@classmethod
def __recursive_parse(cls, body_parts, part, body_number='', body_type=None):
if part is None:
return None
part_type, part_sub_type = IMAPBodyStructurePartUtils.get_part_type_and_part_subtype(part)
if part_type == 'MESSAGE_RFC822':
cls.__add_body_part(body_parts, body_number, body_type, part)
# convert message body_structure at part[8] using BodyData
body_data = BodyData()
part = body_data.create(part[8])
if cls.__is_multipart(part):
body_type = cls.__get_body_type(part)
for i, p in enumerate(part[0], 1):
if body_number == '':
next_body_number = str(i)
else:
next_body_number = body_number + '.' + str(i)
cls.__recursive_parse(body_parts, p, body_number=next_body_number, body_type=body_type)
else:
cls.__add_body_part(body_parts, body_number, body_type, part)
elif cls.__is_multipart(part):
body_type = cls.__get_body_type(part)
for i, p in enumerate(part[0], 1):
if body_number == '':
next_body_number = str(i)
else:
next_body_number = body_number + '.' + str(i)
cls.__recursive_parse(body_parts, p, body_number=next_body_number, body_type=body_type)
else:
if body_number == '':
body_number = '1'
cls.__add_body_part(body_parts, body_number, body_type, part)
return body_parts
# BODYSTRUCTURE examples
body_structures = [
{
'name': 'single text/plain part',
'body_structure':
(b'text', b'plain', (b'charset', b'utf-8'), None, None, b'7bit', 1148, 59, None, None, None, None),
},
{
'name': 'text/plain and text/html',
'body_structure':
(
[
(b'text', b'plain', (b'charset', b'iso-8859-1'), None, None, b'quoted-printable', 426, 15, None, None, None, None),
(b'text', b'html', (b'charset', b'iso-8859-1'), None, None, b'quoted-printable', 1085, 36, None, None, None, None)
],
b'alternative',
(b'boundary', b'_000_CWXP265MB4244C3FA1F3563A988AAE2CABBDF9CWXP265MB4244GBRP_'),
None,
(b'en-US',),
None
),
},
{
'name': 'text/plain and pdf attachment',
'body_structure':
(
[
(b'text', b'plain', (b'charset', b'ISO-8859-15'), None, None, b'quoted-printable', 394, 13, None, (b'inline', None), None, None),
(b'application', b'pdf', (b'name', b'manual.pdf'), None, None, b'base64', 175098, None, (b'attachment', (b'filename', b'manual.pdf')), None, None)
],
b'mixed',
(b'boundary', b'_----------=_1631938636414264302'),
None,
None,
None
),
},
{
'name': 'text/plain and text/html and pdf attachment',
'body_structure':
(
[
(
[
(b'text', b'plain', (b'charset', b'UTF-8'), None, None, b'8bit', 1268, 25, None, (b'inline', None), None, None),
(b'text', b'html', (b'charset', b'UTF-8'), None, None, b'8bit', 10887, 115, None, (b'inline', None), None, None)
],
b'alternative',
(b'boundary', b'alt-60e413d9174229.65052373'),
None,
None,
None
),
(b'application', b'pdf', (b'name', b'summary.pdf'), None, None, b'base64', 187354, None,
(b'attachment', (b'filename', b'summary.pdf')), None, None)
],
b'mixed',
(b'boundary', b'multipart-60e413d9174190.84932644'),
None,
None,
None
),
},
{
'name': 'text/plain, text/html and inline image',
'body_structure':
(
[
(
[
(b'text', b'plain', (b'charset', b'UTF-8'), None, None, b'quoted-printable', 3909, 138, None, None, None, None),
(b'text', b'html', (b'charset', b'UTF-8'), None, None, b'quoted-printable', 21375, 397, None, None, None, None)
],
b'alternative',
(b'boundary', b'000000000000239fe505c86b594b'),
None,
None,
None
),
(b'image', b'png', (b'name', b'image.png'), b'<17afcc25c9bcb971f161>', None, b'base64', 1491868, None,
(b'inline', (b'filename', b'image.png')), None, None)
],
b'related',
(b'boundary',
b'000000000000239fe605c86b594c'),
None,
None,
None
),
},
{
'name': 'text/plain, text/html and inline images and pdf attachment',
'body_structure':
(
[
(
[
(
[
(b'text', b'plain', (b'charset', b'UTF-8'), None, None, b'quoted-printable', 4393, 90, None, None, None, None),
(b'text', b'html', (b'charset', b'UTF-8'), None, None, b'quoted-printable', 12720, 264, None, None, None, None)
],
b'alternative',
(b'boundary', b'0000000000007dda0f05c7b3e2d2'),
None,
None,
None
),
(b'image', b'png', (b'name', b'image.png'), b'<17acdbf96cccb971f161>', None, b'base64', 120514, None,
(b'inline', (b'filename', b'image.png')), None, None),
(b'image', b'png', (b'name', b'image.png'), b'<17acdbf96cccb971f162>', None, b'base64', 78208, None,
(b'inline', (b'filename', b'image.png')), None, None)
],
b'related',
(b'boundary', b'0000000000007dda1005c7b3e2d3'),
None,
None,
None
),
(b'application', b'pdf', (b'name', b'Love letter.pdf'), b'<17acdbf96cc7f74e7e76>', None, b'base64', 591456, None,
(b'attachment', (b'filename', b'Love letter.pdf')), None, None)
],
b'mixed',
(b'boundary', b'0000000000007dda1105c7b3e2d4'),
None,
None,
None
),
},
{
'name': 'text/plain with message/rfc822 attachment',
'body_structure':
(
[
(b'text', b'plain', (b'charset', b'utf-8'), None, None, b'7bit', 35, 7, None, None, None, None),
(b'message', b'rfc822', (b'name', b'Please respond.eml'), None, None, b'7bit', 10034116,
(
b'Sun, 19 Sep 2021 10:04:43 +0200',
b'Please respond',
((b'Peter Mooring', None, b'petermooring', b'gmail.com'),),
((b'Peter Mooring', None, b'petermooring', b'gmail.com'),),
((b'Peter Mooring', None, b'petermooring', b'gmail.com'),),
((b'peterpm@xs4all.nl', None, b'peterpm', b'xs4all.nl'),),
None,
None,
None,
b'<8b678e28-d03a-2bdd-2930-12470235ef9a@gmail.com>'),
(
(b'text', b'plain', (b'charset', b'utf-8'), None, None, b'7bit', 46, 7, None, None, None, None),
(b'text', b'html', (b'charset', b'UTF-8'), None, None, b'quoted-printable', 21375, 397, None, None, None, None),
b'alternative',
(b'boundary', b'------------3F95A42110AABF9E24EC86EB'),
None,
(b'en-US',),
None
),
128759,
None,
(b'attachment', (b'filename', b'Please respond.eml')), None, None
)
],
b'mixed',
(b'boundary', b'------------7323DBBF0E22BDA4B95E42D1'),
None,
(b'en-US',),
None
),
},
{
'name': 'text/plain with message/rfc822 attachment including another message/rfc822',
'body_structure':
(
[
(b'text', b'plain', (b'charset', b'utf-8'), None, None, b'7bit', 35, 7, None, None, None, None),
(b'message', b'rfc822', (b'name', b'Re: My message.eml'), None, None, b'7bit', 10034116,
(
b'Sun, 19 Sep 2021 10:04:43 +0200',
b'Re: My message',
((b'Bob Smith', None, b'bobsmith', b'example.com'),),
((b'Bob Smith', None, b'bobsmith', b'example.com'),),
((b'Bob Smith', None, b'bobsmith', b'example.com'),),
((b'richardroe@example.org', None, b'richardroe', b'example.org'),),
None,
None,
None,
b'<8b678e28-d03a-2bdd-2930-12470235ef9a@example.com>'
),
(
(b'text', b'plain', (b'charset', b'utf-8'), None, None, b'7bit', 46, 7, None, None, None, None),
(b'message', b'rfc822', (b'name', b'Fw: Some email two.eml'), None, None, b'7bit', 10029135,
(
b'Sat, 18 Sep 2021 18:35:47 +0200',
b'Fw: Some email two',
((b'John Doe', None, b'johndoe', b'example.org'),),
((b'John Doe', None, b'johndoe', b'example.org'),),
((b'John Doe', None, b'johndoe', b'example.org'),),
((None, None, b'richardroe', b'example.org'),),
None,
None,
None,
b'<a7dfbf41-1a26-4316-b8b5-1753fc17cd54-1631982946791@3c-example.org>'),
(
(b'text', b'html', (b'charset', b'UTF-8'), None, None, b'7bit', 5053, 89, None, None, None, None),
(b'application', b'pdf', (b'name', b'YZ345.pdf'), None, None, b'base64', 187354, None,
(b'attachment', (b'filename', b'YZ345.pdf')), None, None),
b'mixed',
(b'boundary', b'abmob-49888c7b-3a09-4d10-b119-df9366de9f4c'),
None,
None,
None
),
128656,
None,
(b'attachment', (b'filename', b'Fw: Some email two.eml')),
None,
None
),
b'mixed',
(b'boundary', b'------------3F95A42110AABF9E24EC86EB'),
None,
(b'en-US',),
None
),
128759,
None,
(b'attachment', (b'filename', b'Fw: Some email two.eml')), None, None
)
],
b'mixed',
(b'boundary', b'------------7323DBBF0E22BDA4B95E42D1'),
None,
(b'en-US',),
None
),
},
]
# show examples
for b in body_structures:
print('\nBody structure: {}\n{}'.format(b['name'], '-'*60))
for body_structure_part in IMAPBodyStructureParser.parse(b['body_structure']):
print('{}'.format(body_structure_part))
Ein Wort zu IMAP und Datenschutz
IMAP wurde entwickelt, um Ihre Nachrichten auf einem IMAP -Server zu speichern, so dass sie von mehreren Geräten aus abgerufen werden können. Mit IMAP fordern Sie zunächst nur minimale Daten an. Wenn Sie mehr wollen, werden nur die ausgewählten Teile heruntergeladen. Auch Suchanfragen werden an den IMAP -Server gesendet. Ich persönlich mag IMAP nicht, weil dadurch viel mehr Daten auf dem IMAP -Server verbleiben und die Anzeige bestimmter Anhänge und Suchanfragen auch für das Fingerprinting verwendet werden kann.
Zusammenfassung
Die Verflachung des IMAP BODYSTRUCTURE hat mich Zeit gekostet, da es keine Python -Rezepte im Internet gab. Nach der Lektüre des RFC3501 schien es nicht so schwierig zu sein ... aber ... Da wir den BODYSTRUCTURE selbst entschlüsseln, können wir leicht Fehler machen. Und können wir mit allen Arten von (missgebildeten) BODYSTRUCTUREs umgehen?
Im Internet findet man Informationen über manchmal fehlschlagende Decoder, z.B. von RoundCube. Sie greifen zurück, indem sie die gesamte Nachricht abrufen.
Links / Impressum
IMAP BODYSTRUCTURE: formatted examples
http://sgerwk.altervista.org/imapbodystructure.html
IMAPClient
https://imapclient.readthedocs.io/en/2.2.0/index.html
INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
https://datatracker.ietf.org/doc/html/rfc3501
Neueste
- Ausblenden der Primärschlüssel der Datenbank UUID Ihrer Webanwendung
- Don't Repeat Yourself (DRY) mit Jinja2
- SQLAlchemy, PostgreSQL, maximale Anzahl von Zeilen pro user
- Anzeige der Werte in den dynamischen Filtern SQLAlchemy
- Sichere Datenübertragung mit Public Key Verschlüsselung und pyNaCl
- rqlite: eine hochverfügbare und distverteilte SQLite -Alternative
Meistgesehen
- Verwendung von Pythons pyOpenSSL zur Überprüfung von SSL-Zertifikaten, die von einem Host heruntergeladen wurden
- Verwendung von UUIDs anstelle von Integer Autoincrement Primary Keys mit SQLAlchemy und MariaDb
- Verbindung zu einem Dienst auf einem Docker -Host von einem Docker -Container aus
- PyInstaller und Cython verwenden, um eine ausführbare Python-Datei zu erstellen
- SQLAlchemy: Verwendung von Cascade Deletes zum Löschen verwandter Objekte
- Flask RESTful API Validierung von Anfrageparametern mit Marshmallow-Schemas