Using Delphi 11.
After downloading an email using TIdIMAP4
, scanning through the MessageParts
, how do I detect if a MessagePart
contains a MIME encoded attachment, and how do I decode this into the original format (Image, documents, etc)?
procedure TImapForm.ProcessEmail(MSG: TIdMessage);
begin
ContainsAttachement := false;
if Msg.MessageParts.Count > 0 then
begin
for i := 0 to Pred(Msg.MessageParts.Count) do
begin
if Msg.MessageParts.Items[i] is TIdText then
begin
// Process Text-only message here (Don't want HTML)
end else
begin
ContainsAttachement := true;
// if Msg.MessageParts[i].MessageParts.Encoding = meMIME then
if MSG.ContentTransferEncoding = 'base64' then //??
if Msg.MessageParts.Items[i].IsEncoded then //??
begin
// How to actually decode the MessagePart to a binary file?
end;
end;
end;
end;
end;
Email example:
This is a multi-part message in MIME format.
--------------wt6iyRLyQwO4w89MYm2jGb0w
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
test
--------------wt6iyRLyQwO4w89MYm2jGb0w
Content-Type: image/jpeg; name="Bart.jpg"
Content-Disposition: attachment; filename="Bart.jpg"
Content-Transfer-Encoding: base64
/9j/4AAQSkZJRgABAQEASABIAAD/4ThFRXhpZgAASUkqAAgAAAAMAA4BAgAgAAAAngAAAA8B
AgAUAAAAvgAAABABAgAHAAAA1gAAABIBAwABAAAAAQAAABoBBQABAAAA7gAAABsBBQABAAAA
9gAAACgBAwABAAAAAgAAADEBAgAIAAAA/gAAADIBAgAUAAAAHgEAABMCAwABAAAAAgAAAGmH
etc.
TIdMessage
already handles this for you. Look for TIdAttachment
message parts, eg:
procedure TImapForm.ProcessEmail(MSG: TIdMessage);
var
MsgPart: TIdMessagePart;
i: Integer;
begin
ContainsAttachement := false;
for i := 0 to Pred(Msg.MessageParts.Count) do
begin
MsgPart := Msg.MessageParts[i];
if MsgPart is TIdText then
//or: if MsgPart.PartType = mcptText then
begin
...
end
else if MsgPart is TIdAttachment then
//or: if MsgPart.PartType = mcptAttachment then
begin
ContainsAttachement := true;
TIdAttachment(MsgPart).SaveToFile(...);
end;
end;
end;
That being said, MIME-encoded emails can have complex structures (see HTML Messages on Indy's blog, for example). Because of this, message parts can be nested, and have relationships with other message parts. So, the correct way to process standalone attachments (as opposed to HTML-embedded images/media, for instance) in a MIME email is to loop backwards from last part to first part (because MIME parts are ordered from least complex to most complex) looking for attachments whose ParentPart
property is -1
(ie, a top-level part).
In general, if you find a message part whose ContentType
property is multipart/...
(like multipart/related
) that interests you, then you can dig into its nested content by looping again looking for message parts whose ParentPart
property refers to that message part that interested you. And so on, and so on, as deep as you need to go.
For example:
procedure TImapForm.ProcessEmail(MSG: TIdMessage);
var
MsgPart: TIdMessagePart;
i: Integer;
begin
ContainsAttachement := false;
if Msg.MessageParts.Count = 0 then
begin
if IsHeaderMediaType(Msg.ContentType, 'text/plain') then
begin
// Process Msg.Body here ...
end;
end
else
begin
for i := Pred(Msg.MessageParts.Count) downto 0 do
begin
MsgPart := Msg.MessageParts[i];
if MsgPart.ParentPart = -1 then
begin
if MsgPart is TIdAttachment then
begin
ContainsAttachement := true;
TIdAttachment(MsgPart).SaveToFile(...);
end
else if MsgPart is TIdText then
begin
if IsHeaderMediaType(MsgPart.ContentType, 'multipart') then
begin
// process nested parts whose ParentPart is MsgPart.Index ...
end
else if IsHeaderMediaType(MsgPart.ContentType, 'text/plain') then
begin
// Process TIdText(MsgPart).Body here ...
end;
end;
end;
end;
end;
end;