IMAPClient en het afvlakken van de BODYSTRUCTURE
Het afvlakken van de BODYSTRUCTURE vereist dat je begint met het lezen van de RFC3501.
Applicatie-ontwikkelaars willen bewezen oplossingen gebruiken om een applicatie te maken. Vaak werkt dit, maar met het IMAPClient pakket ontbreken er een aantal zaken.
Het hele idee van IMAP is om alleen te krijgen wat je vraagt. Stel dat je een e-mail hebt met veel bijlagen, maar je wilt er maar één van bekijken of downloaden. Om dit te kunnen doen heb je de 'body_number' van deze bijlage nodig en vervolgens FETCH dit deel.
Op het internet zie je mensen die het hele bericht downloaden, maar dat is niet de manier om dit te doen! Hier presenteer ik een oplossing om de body_numbers van alle delen van een e-mail bericht te krijgen.
Het afvlakken van de BODYSTRUCTURE
Ik heb hier zelf mee geworsteld en om op gang te komen heb ik wat code gebruikt die ik op het internet had gevonden, maar dat was van beperkt nut. Tijd om de RFC3501 te gaan lezen, zie onderstaande links. Een IMAP e-mail bericht bestaat niet alleen uit bijlagen zoals images en PDF bestanden, maar de bijlagen kunnen zelf ook berichten zijn, wat betekent dat onze code recursie moet gebruiken.
Wat ik wil is een lijst van body_numbers die gebruikt kan worden om FETCH het deel (de delen) dat we willen hebben. We kunnen deze bewerking 'afvlakken van de BODYSTRUCTURE' noemen, omdat we van recursies naar een lijst gaan. Tijdens dit proces genereren we de body_numbers.
MULTIPART/ALTERNATIVE, MULTIPART/MIXED, MULTIPART/RELATED, ...
E-mailberichten zijn meestal opgebouwd uit items die aan elkaar gerelateerd zijn. Er zijn verschillende soorten relaties, bijvoorbeeld:
- ALTERNATIVE: de onderdelen in alternatief hebben dezelfde inhoud, zodat de mail client kan kiezen welke getoond moet worden
- RELATED: de onderdelen moeten samen worden gepresenteerd, niet alternerend. Bijgevolg worden ze gecombineerd. bv. inline afbeelding
- MIXED: de delen bevatten verschillende informatie en dienen niet samen te worden getoond.
Het document "IMAP BODYSTRUCTURE: formatted examples" geeft een aardige inleiding, zie de links hieronder.
Hier is een voorbeeld van een ALTERNATIVE relatie. De BODYSTRUCTURE die door IMAPClient wordt teruggegeven is:
(
[
(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 geeft ons een lijst van ALTERNATIVE items. We kunnen kiezen om ofwel de platte tekst of het HTML gedeelte te tonen. De afgeplatte body_parts zijn, eerste nummer is de body_number:
1 - ALTERNATIVE : TEXT, text/plain, iso-8859-1
2 - ALTERNATIVE : TEXT, text/html, iso-8859-1
Hier is hetzelfde voorbeeld met een PDF hulpstuk toegevoegd:
(
[
(
[
(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
)
De afgevlakte body_parts zijn, eerste nummer is de 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
Waar komen de body_numbers vandaan?
Wij krijgen de body_numbers niet van de IMAP server. In plaats daarvan krijgen we de BODYSTRUCTURE van de IMAP server en moeten we daaruit de body_numbers genereren. In de bovenstaande voorbeelden is dit niet moeilijk. Maar het wordt ingewikkelder met bijgevoegde berichten.
De structuur van de BODYSTRUCTURE
Om de BODYSTRUCTURE te begrijpen heb ik wat tekst gekopieerd uit RFC3501:
De basisvelden van een niet-multipart body part staan in de onderstaande volgorde:
- body type
Een tekenreeks met de naam van het inhoudstype media zoals gedefinieerd in [MIME-IMB]. -
body subtype
Een tekenreeks die de naam geeft van het inhoudssubtype zoals gedefinieerd in [MIME-IMB]. -
body parameter parenthesized list
Een tussen haakjes geplaatste lijst van attributen/waardeparen [bv. ("foo" "bar" "baz" "rag") waarbij "bar" de waarde is van "foo" en "rag" de waarde is van "baz"] zoals gedefinieerd in [MIME-IMB]. -
body id
Een tekenreeks die de inhoud-id geeft zoals gedefinieerd in [MIME-IMB]. -
body description
Een tekenreeks die de inhoud geeft zoals gedefinieerd in [MIME-IMB]. -
body encoding
Een tekenreeks die de codering voor inhoudsoverdracht geeft, zoals gedefinieerd in [MIME-IMB]. -
body size
Een getal dat de grootte van de body in bytes aangeeft. Merk op dat deze grootte de grootte is in de overdrachtscodering en niet de resulterende grootte na decodering.
Een body type van het type MESSAGE en subtype RFC822 bevat onmiddellijk na de basisvelden de structuur van de enveloppe, de structuur van de body en de omvang in tekstregels van het ingekapselde bericht.
Een body type van het type TEXT bevat, onmiddellijk na de basisvelden, de omvang van de body in tekstregels. Merk op dat deze grootte de grootte is in de codering van de inhoudsoverdracht en niet de resulterende grootte na eventuele decodering.
Uitbreidingsgegevens volgen op de basisvelden en de boven opgesomde typespecifieke velden. Uitbreidingsgegevens worden nooit teruggezonden met de BODY-afleiding, maar kunnen worden teruggezonden met een BODYSTRUCTURE -afleiding. Indien er uitbreidingsgegevens aanwezig zijn, MOETEN deze in de gedefinieerde volgorde staan.
Merk op dat de body type van het type MESSAGE en subtype RFC822 recursie introduceert. Wanneer we dit tegenkomen, verwerken we dit bericht als een nieuw bericht, extraheren body_number's, enz. En dit bericht kan weer een of meer andere berichten bevatten.
Volgens de RFC3501, bevat elk bericht een enveloppe structuur, en een body structuur. De body-structuur van het bericht is de nieuwe body-structuur die wij moeten verwerken.
Geneste berichten voorbeeld
Hier is een voorbeeld van een bericht dat een ander bericht bevat dat een ander bericht met een bijlage bevat. De BODYSTRUCTURE die door IMAPClient wordt geretourneerd is:
(
[
(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
)
De afgevlakte body_parts zijn, eerste nummer is de 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
De BODYSTRUCTURE van geneste berichten vastleggen
Als je naar het voorbeeld van geneste berichten hierboven kijkt, zul je zien dat geneste berichten geen lijsten bevatten, zoals het bericht op het hoogste niveau. Ik beschouw dit als een bug, maar het kan ook een ontwerpbeslissing zijn.
Hoe dan ook, IMAPClient bevat een klasse die we kunnen gebruiken om het geneste bericht BODYSTRUCTURE te converteren naar een bericht van het hoogste niveau BODYSTRUCTURE.
body_data = BodyData()
body_structure = body_data.create(nested_message_body_structure_part)
Nu bevat het geneste bericht BODYSTRUCTURE lijsten en kan het op dezelfde manier verwerkt worden als het top niveau BODYSTRUCTURE.
De klasse BodyStructurePart en deel-typen
Flatten betekent dat we een lijst van BodyStructurePart objecten maken. Een BodyStructurePart klasse bevat alle informatie om verdere verwerking te doen. Zij moet tenminste het volgende bevatten:
- body_number: de body_number
- body_type: ALTERNATIVE, MIXED, enz.
- body_part: het eigenlijke deel van de BODYSTRUCTURE
Daarnaast heb ik attributen toegevoegd:
- part_type
- part_subtype
- content_type
Een part_type kan zijn, zie ook RFC3501 hierboven:
- MESSAGE_RFC822
- TEXT
- NON_MULTIPART
Een part_subtype, gebruikt met part_type = NON_MULTIPART, kan zijn:
- ATTACHMENT
- INLINE
- OTHER
De BODYSTRUCTURE parser code
En tenslotte is hier de parser code. Het bevat drie klassen:
- IMAPBodyStructurePartUtils
- IMAPBodyStructurePart
- IMAPBodyStructureParser
De klasse IMAPBodyStructureParser heeft een parse-methode die wordt aangeroepen met de BODYSTRUCTURE die door IMAPClient wordt teruggegeven. Deze methode geeft een lijst van IMAPBodyStructurePart objecten terug die in onze code kunnen worden gebruikt.
Ik heb de code en voorbeelden in een enkel bestand gezet voor het geval je het wilt proberen:
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))
Een woord over IMAP en privacy
IMAP is ontworpen om je berichten op een IMAP server te laten staan, ze kunnen vanaf meerdere apparaten benaderd worden. Met IMAP vraagt u in eerste instantie slechts minimale gegevens op. Als u meer wilt, worden alleen de geselecteerde delen gedownload. Zoekverzoeken worden ook naar de IMAP server gestuurd. Persoonlijk houd ik niet van IMAP omdat het veel meer van je gegevens op de IMAP server laat staan en het bekijken van specifieke bijlagen en zoek verzoeken ook gebruikt kan worden voor fingerprinting.
Samenvatting
Het plat maken van de IMAP BODYSTRUCTURE kostte me tijd omdat er geen Python recepten op het internet te vinden waren. Na het lezen van de RFC3501 bleek het niet zo moeilijk ... maar ... Omdat we de BODYSTRUCTURE zelf ontcijferen kunnen we gemakkelijk fouten maken. En kunnen we alle soorten (misvormde) BODYSTRUCTUREs aan?
Op het internet is informatie te vinden over soms falende decoders, b.v. van RoundCube. Zij vallen terug door het hele bericht op te halen.
Links / credits
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
Recent
- Database UUID primaire sleutels van je webapplicatie verbergen
- Don't Repeat Yourself (DRY) met Jinja2
- SQLAlchemy, PostgreSQL, maximum aantal rijen per user
- Toon de waarden in SQLAlchemy dynamische filters
- Veilige gegevensoverdracht met Public Key versleuteling en pyNaCl
- rqlite: een alternatief voor SQLite met hoge beschikbaarheid en distributed
Meest bekeken
- Met behulp van Python's pyOpenSSL om SSL-certificaten die van een host zijn gedownload te controleren
- Gebruik van UUIDs in plaats van Integer Autoincrement Primary Keys met SQLAlchemy en MariaDb
- Maak verbinding met een dienst op een Docker host vanaf een Docker container
- PyInstaller en Cython gebruiken om een Python executable te maken
- SQLAlchemy: Gebruik van Cascade Deletes om verwante objecten te verwijderen
- Flask RESTful API verzoekparametervalidatie met Marshmallow-schema's