Enough-Software / enough_mail

IMAP, POP3 and SMTP clients for Dart developers. Contains both low level as well as a high level API.
Mozilla Public License 2.0
104 stars 55 forks source link

MIME: Extract attachments from an email message #49

Open aliheader opened 4 years ago

aliheader commented 4 years ago

Need some documentation to fetch the attachment detail from the Mime Message and how we find part id/no for attachments to pass in the BODY[part id/no]. Actually, I manage to fetch the attachment by fetching the specific body part from Body, which was working fine before the 0.0.18 version.

Code

var fetchResponse = await S.sImapClient.fetchMessagesByCriteria('$sequenceID (BODY[$part])');
robert-virkus commented 4 years ago

I am not sure I understand your problem correctly, but if it is about accessing the individual mime parts, there are basically 2 ways:

  1. Fetch the whole message with (BODY[]) or(BODY.PEEK[]) You can then traverse the message and all its parts with a a recursive mechanism.
  2. If it is a flat message, fetch (BODYSTRUCTURE BODY[1]) for example, and then access the individual parts with for example mimeMessage.body.getBodyPart(1); Also compare https://pub.dev/documentation/enough_mail/latest/mime_message/BodyPart-class.html

AFAIK most IMAP servers do index ENVELOPE but not BODYSTRUCTURE, so maybe it is wise to download the complete BODY[] for at least the smaller messages.

Does this help?

aliheader commented 4 years ago

I did as you suggest to fetch the whole message with (BODY[]) and (BODY.PEEK[]) but when try to traverse the message parts. null exception occurred on parts.

LOG

I/flutter (21344): C: a20 FETCH 56 (BODY[])
I/flutter (21344): S: * 56 FETCH (BODY[] {316914}
I/flutter (21344): S: a20 OK Fetch completed (0.002 + 0.000 + 0.001 secs).
E/flutter (21344): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The getter 'parts' was called on null.
E/flutter (21344): Receiver: null
E/flutter (21344): Tried calling: parts
E/flutter (21344): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
E/flutter (21344): #1      _MailDetailPageState.fetchMessageData (package:halocare/pages/email_client/mail_detail_page.dart:55:28)

Note In the first comment, I said that if I want to fetch attachment/file base64 encoded string, then how can I do that?

robert-virkus commented 4 years ago

Please try calling mime Message.parse(); manually before you access any individual parts. Usually this is called indirectly for example when reading the content type header, but I guess I need to do that as well when the parts are accessed directly.

robert-virkus commented 4 years ago

Please also note that mime messages are pretty flexibel when it comes to how they are nested. If you have a complex case it can help to fetch the BODYSTRUCTURE and then just print the mime Message.body object to get a feel.

The outer layer could be multipart/mixed message that contains a multipart/alternative part that in turn contains a text/plain and a text/html part. The outer multipart/mixed part can then contain other parts with attachments. And this is just one example.

My advise would be to recursively visit all parts and collect any with an "attachment" content disposition, if you are mostly interested in the attachments.

TheOneWithTheBraid commented 4 years ago

I am having trouble with a message containing two attachments: the second attachment (part) is properly split but the first part returns the message itself and the first attachment:

              message.parts.forEach((element) {
                print(element.decodeContentText());
              });

The first part's decodeContentText() returns the following:

[message, message, message and still more text...]
Regards,
name

--=20
PGP Fingerprint: CD80 85CB B8E8 XXXXXXXXX

--------------61CD466427BA97004CEE95DC
Content-Type: application/pgp-keys;
 name="OpenPGP_XXXXXXXXX.asc"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="OpenPGP_XXXXXXXXX.asc"

-----BEGIN PGP PUBLIC KEY BLOCK-----

xjMEXl71ZRYJKwYBBAHaRw8BAQdAsYRpLDjPzRarde9GO3HmdfmWNhqSeWu1khSkqfcZL/HNJ=
Etu
b2JsYXVjaCA8aW5nd2Vyeml0cm9uZUByaXNldXAubmV0PsKWBBMWCAA+FiEEzYCFy7jokYA4X=
wqa
0386y6+aOKgFAl5e9WUCGwMFCQlmAYAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ0386y=
6+a
OKg6ZwD+L1A6PDIh9sa3bQefTkS/XGfgGk4EDKHNbcDg6+9Q26ABAJskBkZ5Jhr1n8ENo530K=
elm
[...]

Is this expected or an issue?

robert-virkus commented 4 years ago

First of all: it's great to see PGP support being worked on!

Secondly, would it be possible to get the full response as retrieved by a FETCH $id (BODY[]) ? I would need to understand the message structure to advise you or to (ideally) fix the bug.

TheOneWithTheBraid commented 4 years ago

I am running the following code

              print(message.parts);
              print(message.bodyRaw);
              message.parts.forEach((element) {
                print(element.decodeContentText());
              });
The dart output ``` flutter: [Instance of 'MimePart', Instance of 'MimePart'] flutter: This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --jsRvMCvIu46WpNX1JGpxzIxzfAm6xTTQ6 Content-Type: multipart/mixed; boundary="BHExnvuVOviQxAIGaEirfgZbVhPGKVh6z"; protected-headers="v1" From: =?UTF-8?Q?XXXXXXX_XXXXXX?= To: Xxxxxxx Message-ID: <05fb895f-e6e8-4e40-fc9e-1a86a2b7ac55@xxxxxxxx.org> Subject: Re: XXXXXX References: <66704825-5855-4783-b7c3-d48ee34c46d8@xxxxx.re> In-Reply-To: <66704825-5855-4783-b7c3-d48ee34c46d8@xxxxxx.re> --BHExnvuVOviQxAIGaEirfgZbVhPGKVh6z Content-Type: multipart/mixed; boundary="------------831B4B68BAC422FAB7101CF9" This is a multi-part message in MIME format. --------------831B4B68BAC422FAB7101CF9 Content-Type: multipart/alternative; boundary="------------E7938C4510EDF90BE5C237F5" --------------E7938C4510EDF90BE5C237F5 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: quoted-printable THE MESSAGE TEXT.... Regards ..... Am 01.11.2020 um 18:30 schrieb XXXXXX: > A quote --------------E7938C4510EDF90BE5C237F5 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable

XXXXX,

SOME HTML

Am 01.11.2020 um 18:30 schrieb XXXXXXX:<= br>
SOME HTML
--------------E7938C4510EDF90BE5C237F5-- --------------831B4B68BAC422FAB7101CF9 Content-Type: application/pgp-keys; name="OpenPGP_0xXXXXXXXXX.asc" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="OpenPGP_0xXXXXXXXXX.asc" -----BEGIN PGP PUBLIC KEY BLOCK----- [...] ALkh8XOCbFCWAP9OpfmHxIuwbmK6yNuoQhygxjqh4gcuE3nrJYYbt8/vAw=3D=3D =3DLyed -----END PGP PUBLIC KEY BLOCK----- --------------831B4B68BAC422FAB7101CF9-- --BHExnvuVOviQxAIGaEirfgZbVhPGKVh6z-- --jsRvMCvIu46WpNX1JGpxzIxzfAm6xTTQ6 Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="OpenPGP_signature" -----BEGIN PGP SIGNATURE----- wnsEABYIACMWIQS [...] b6oUGuLbJCwEAmL28F+QOf1nLe3ABYV1J/6aTDZir UckHnSueOzINHwA= =bNL9 -----END PGP SIGNATURE----- --jsRvMCvIu46WpNX1JGpxzIxzfAm6xTTQ6-- flutter: --BHExnvuVOviQxAIGaEirfgZbVhPGKVh6z Content-Type: multipart/mixed; boundary="------------831B4B68BAC422FAB7101CF9" This is a multi-part message in MIME format. --------------831B4B68BAC422FAB7101CF9 Content-Type: multipart/alternative; boundary="------------E7938C4510EDF90BE5C237F5" --------------E7938C4510EDF90BE5C237F5 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: quoted-printable THE MESSAGE Am 01.11.2020 um 18:30 schrieb XXXXX: > A quote > XXXXX --------------E7938C4510EDF90BE5C237F5 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable

Hey,

SOME HTML
Am 01.11.2020 um 18:30 schrieb XXXXXX:<= br>
SOME HTML
--------------E7938C4510EDF90BE5C237F5-- --------------831B4B68BAC422FAB7101CF9 Content-Type: application/pgp-keys; name="OpenPGP_0xXXXXXXXX.asc" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="OpenPGP_0xXXXXXXXX.asc" -----BEGIN PGP PUBLIC KEY BLOCK----- xjMEX3WlbBYJKwYBBAHaRw8BAQdAiOyi4Pf5fXZM189wNpyYktQaPP9iHCrwnG5I7ujsAE/NM= UVu [...] yZcLBQJfdaVsAhsMBQkJZgGAAAoJEBCuh7UoyZcLAoIA/itDl86casVLjVUz2kA5MjVMVDOFt= Ko6 ALkh8XOCbFCWAP9OpfmHxIuwbmK6yNuoQhygxjqh4gcuE3nrJYYbt8/vAw=3D=3D =3DLyed -----END PGP PUBLIC KEY BLOCK----- --------------831B4B68BAC422FAB7101CF9-- --BHExnvuVOviQxAIGaEirfgZbVhPGKVh6z-- flutter: -----BEGIN PGP SIGNATURE----- wnsEABYIACMWIQS+FDsyd6/bhav9Y7AQroe1KMmXCwUCX [...] UckHnSueOzINHwA= =bNL9 -----END PGP SIGNATURE----- ```
robert-virkus commented 4 years ago

Many thanks, will look into it!