Repository navigation
v0.8.0 — back on fast-mail-parser
Installed as fast-mail-parser again
pip install fast-mail-parserReleases 0.6.0–0.7.0 went out as fast-mail-parser-ng because the original PyPI name belonged to an account this project no longer controlled, frozen at 0.2.5 from June 2022. Ownership has since been transferred, so releases go back to the original name.
The import path is unchanged, as it has been throughout: from fast_mail_parser import parse_email. If you are on fast-mail-parser-ng, change the name in your requirements file and nothing else. That project stays on PyPI so nothing pinning it breaks, but it receives no further releases.
New APIs
parse_email_tree(payload) + walk(part) — the MIME tree with its structure intact. parse_email returns a flat projection, and any flattening loses something: which text/html corresponds to which text/plain sibling, or where a bounce's embedded message begins. message/rfc822 parts are now parsed rather than opaque. Tree topology is asserted against the stdlib's walk() across the whole corpus, and costs −0.5% versus a flat parse.
parse_email(payload, mode="metadata") — headers and the attachment inventory with nothing decoded, 3.7x faster on a message that is 99% attachment by content. Attachments carry encoded_size. The mode picks the return type through typed overloads, so callers of the default path see no change.
PyMail.warnings and parse_email(payload, strict=True) — the lossy repairs a parse performed, reported instead of swallowed. Five kinds, each mapped onto the existing exception hierarchy. warnings == [] is the contract, and it costs nothing measurable.
Fixes
headerskeys now come back in wire order, stably across parses. They came from a RustHashMapwhose iteration order is randomised per instance, so identical bytes produced a different key order every time — forty distinct orders in forty parses.- A missing header/body separator is repaired instead of eating the body. A real-world message that omits it used to lose its first body part silently; the stdlib calls the defect
MissingHeaderBodySeparatorDefect. - An internal panic raises
ParseErrorrather than PyO3'sPanicException, which derives fromBaseExceptionand so slipped past theexcept Exceptionaround a worker's parse call. parse_many(payloads, threads=0)raisesValueErrorinstead of silently meaning "the default".
Performance
Batch parsing is 27% faster. bytes payloads are no longer copied before parsing: parse_many used to duplicate the whole batch before parsing any of it. Batch time is now within measurement error of parsing each message individually.
This also removes the reason to avoid parse_many for large messages — it used to be ~1.5x slower than a Python thread pool there, and the two are now level, while it stays ~12x faster for the many-small-messages case a mail pipeline actually has.
Full detail in the changelog.