1.12.0
Highlights
SwiftMail 1.12.0 adds a parser for Outlook .msg (#237), so mail saved as files parses the same on either platform instead of only where it was saved as .eml. Around it, this release is mostly correctness in how headers and parameters are written and read (#226, #230, #233), and better diagnostics when a server refuses something (#221, #227, #231).
One behavior change is worth reading before upgrading: Message.bodies, .attachments and .cids no longer reach inside an attached message/rfc822. It affects IMAP-fetched messages too, not only .msg.
Changes
Outlook .msg parsing (#237)
- New
MSGParser.parse(_:)andMessage(msgData:), producing the sameMessagean.emldoes, so parts, attachments, addresses and dates keep working downstream. - Outlook usually stores no HTML at all — the rich body is
PR_RTF_COMPRESSED, and what that decompresses to is normally the original HTML encapsulated in RTF. Recovering it needs LZFu decompression (MS-OXRTFCP) and de-encapsulation (MS-OXRTFEX), both implemented here. - The body is classified after decompression and never rendered:
\fromhtml1becomes atext/htmlpart,\fromtextis dropped as a duplicate ofPR_BODY, and a genuinely rich-text body is passed through asapplication/rtffor a consumer to render. - Embedded messages are followed recursively and nested under their parent's section. New
Message.embeddedMessagesreturns the immediate children, each renumbered as though parsed on its own, so the same code reads a forwarded message at any depth. - Attachments come with their filename, MIME type and bytes. Inline versus attachment is decided by
ATT_MHTML_REFinPR_ATTACH_FLAGS, not by the presence of a Content-ID — Outlook gives almost every attachment an ID. - Behavior change:
Message.bodies,.attachmentsand.cidsno longer reach inside an attachedmessage/rfc822. An attached message is itself one part; what is nested under it belongs to that message and is reached throughembeddedMessages. Previously a mail forwarding an HTML message but writing only plain text itself reported the forwarded HTML as its own body, and forwarded attachments were counted twice. - The container reader treats its input as hostile: sector numbers are range-checked, chain walks carry visited sets, declared sizes are not trusted past the bytes present, and embedded-message recursion is depth-capped.
- Closes #235.
Header and parameter encoding (#226, #230, #233)
- Header values and display names that cannot be written literally are now encoded rather than emitted raw (#226, supersedes #215).
- MIME parameters are encoded, and parameter parsing is anchored to the RFC 2045 grammar (#230, supersedes #216).
- RFC 2231 continuations are read in one pass, and every charset the platform names is honored, fixing two regressions from #230 (#233).
Diagnostics and failure reporting
SEARCHreturningBADCHARSETis surfaced as a typed error, and response codes are kept in search failures (#227).- SMTP
login()failures carry the server's reply (#231). - The SASL mechanism is judged after the channel is prepared rather than against a cleared snapshot (#221).
- An authenticated IMAP session now requires a live channel (#224, supersedes #223).
API surface
- Validated partial IMAP body part fetching (#228, supersedes #219).
Reply-Tois exposed inMessageInfometadata (#232, resolves #217).supportsMoveis exposed, mirroringsupportsUIDPlus(#225, supersedes #214).- Gmail attributes are exposed on named IMAP connections (#220).
Other
SEARCHsendsCHARSET UTF-8when a criterion carries non-ASCII text (#222).ProcessInfo.processInfo.hostNameis no longer called, for privacy (#229, supersedes #218).- Test fix: the fetched message count is required before indexing in header fallback tests (#234).
Full changelog: 1.11.0...1.12.0