angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

IMAPClient und die Verflachung der BODYSTRUCTURE

Die Reduzierung der BODYSTRUCTURE setzt voraus, dass Sie mit der Lektüre des RFC3501 beginnen.

27 September 2021 Aktualisiert 27 September 2021
In Email
post main image
https://unsplash.com/@2hmedia

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

Mehr erfahren

Email IMAP

Einen Kommentar hinterlassen

Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.

Kommentare

Eine Antwort hinterlassen

Antworten Sie anonym oder melden Sie sich an, um zu antworten.