Library / SDK
mailgun/flanker avatar
mailgun/flanker

mailgun/flanker: Python email address and MIME parsing

Python email address and Mime parsing library

1,647 stars211 forksPythonApache-2.0

At a glance

What is it?
Flanker is a Python library for parsing email addresses and MIME messages. It provides permissive and strict address handling, optional validation, structured headers, and decoded MIME parts, while its README keeps Python 3 support qualified.
Who is it for?
Developers processing mailbox strings or MIME messages in Python can adopt Flanker when permissive parsing and Mailgun-oriented validation fit their code. Projects that require a modern Python support policy should first inspect Python 3 compatibility with their exact runtime and dependency versions.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Flanker's address and MIME parsing scope

Flanker targets code that receives raw email data from forms, APIs, files, or message-processing pipelines. It separates that work into two modules: `flanker.addresslib` parses mailbox and address-list strings, while `flanker.mime` parses complete MIME messages. This makes it relevant to Python applications that need normalized address objects, rejection information for invalid entries, or access to the individual parts of a multipart message.

The library is not presented as a full email client. The README does not document SMTP sending, mailbox retrieval, attachment storage, or delivery tracking as features. Its documented scope is parsing. That boundary makes it suitable for code at the ingress edge of an email system, before application code decides what to do with a message or whether to accept an address.

Flanker was written by the Mailgun Team and is used by Mailgun in production with Python 2.7, according to the README. The project identifies Python 2.7 as its production version in the documentation it provides, while `setup.py` classifies releases for Python 2 and Python 3.6. The README also warns that the team did not use Flanker with Python 3 internally and only knew that its tests passed with Python 3.6. That qualification matters more than the broader packaging metadata for an adopter choosing a runtime today.

Mailbox parsing, strict mode, and partial results

The address API can parse a mailbox containing a display name, reject one invalid string with `None`, or isolate the address portion by setting `addr_spec_only=True`. For collections, `parse_list()` returns the addresses it recognizes. Passing `as_tuple=True` also returns the unparsable portions, which gives calling code enough information to distinguish successful input from rejected input without losing the invalid segments.

This API supports both tolerant and strict workflows. In the README's address-list example, `@example.com` is omitted from the parsed result even when the list contains two valid addresses. With `strict=True`, the same call excludes invalid entries from its result. The documentation does not describe an exception for strict mode, so applications should not assume strict parsing guarantees that the entire input was valid. They should inspect the list length or use the tuple form if rejection reporting is required.

Address objects provide a parsed representation rather than leaving the caller to split addresses on commas or extract angle brackets. This is relevant for mailbox strings such as `Foo <[email protected]>`. Flanker places the address library at the center of its API instead of treating address syntax as an incidental part of MIME handling, which is useful for services that accept sender or recipient fields separately from complete RFC-style messages.

DNS-backed validation and its extra dependency

Flanker offers a more demanding layer through `validate_address()` and `validate_list()`. The README defines address validation as parsing combined with DNS checks, MX existence checks, and ESP grammar checks. `validate_address()` returns the validated mailbox in its example, while `validate_list(..., as_tuple=True)` separates valid addresses from unparsable portions.

This validation is not part of the base installation alone. `setup.py` places `dnsq>=1.1.6` and `redis>=2.7.1` in the `validator` extra rather than in `install_requires`. The README does not provide a dedicated validation installation command or explain the Redis dependency's role. An adopter should inspect packaging behavior rather than inventing a command.

Validation also has an operational consequence. It reaches beyond string syntax into DNS and MX state, meaning behavior can depend on external resolution and current mail routing. The README does not specify timeouts, caching, retry behavior, or the treatment of temporary DNS failures. Code should therefore distinguish an invalid address from infrastructure failure only if the API itself exposes that distinction. The shown return values do not make that failure model explicit.

MIME parsing exposes headers, parts, and decoded bodies

The MIME API converts a complete message string into an object whose headers are available as a Unicode-aware, multi-value dictionary. In the documented example, a structured `Content-Type` header is represented with its main value and parameter dictionary. Other headers remain ordinary name-value entries. This gives callers access to message metadata without reimplementing MIME header handling.

The parsed object exposes `content_type` predicates such as `is_multipart()`, `is_singlepart()`, and `is_message_container()`. For the sample `multipart/alternative` message, `is_multipart()` returns `True`. The top-level `body` is `None` because the content is divided into parts. Iterating over `msg.parts` yields separate `text/plain` and `text/html` parts, each with a decoded body in the decoded form shown by the README.

Flanker also has an `enclosed` member. It is `None` for the sample because that message does not contain an enclosed message. The distinction between `body`, `parts`, and `enclosed` prevents callers from treating every message as one flat text value. For attachment policies, however, the README does not document filename extraction, attachment serialization, or a disposition helper, so this documentation does not establish whether Flanker should be the only layer handling file attachments.

Installing Flanker and parsing the first mailbox

The README offers installation through `pip` or a Git clone. It says Python header files are required and gives distribution-specific commands. Those commands use `python-dev` on Ubuntu and `python-devel` on Fedora, as documented. Select the command matching the build environment rather than running both.

The documented Ubuntu installation command is:

bash
sudo apt-get install python-dev

The README's Fedora alternative is:

bash
sudo yum install python-devel

Install the released package with the documented command:

bash
pip install flanker

A source checkout follows this documented workflow:

bash
git clone [email protected]:mailgun/flanker.git
cd flanker
pip install -e .

For a first address-parsing use, the README gives this Python 2-era example. The warning about Python 3 means the exact runtime still needs local verification:

python
from flanker.addresslib import address
address.parse('Foo [email protected]')

The README's expected result is `Foo <[email protected]>`. An invalid address such as `@example.com` is documented as returning `None`. This first use exercises parsing only. It does not invoke DNS or MX validation.

Reading a multipart message with `flanker.mime`

A first MIME use begins by placing the complete MIME message in `message_string` and passing it to `mime.from_string()`. The README's sample defines `message_string` as a `multipart/alternative` message containing `text/plain` and `text/html` parts.

The core parsing operation is:

python
from flanker import mime
msg = mime.from_string(message_string)

After parsing, callers can query the content type and iterate over parts. The documented example formats each part's `Content-Type` and decoded `body`:

python
for part in msg.parts:
    print 'Content-Type: {} Body: {}'.format(part, part.body)

For the sample message, the content-type predicate returns `True`. Iteration prints one `text/plain` part containing `Hello, *Alice*` and one `text/html` part containing the HTML form of the same greeting. The top-level `msg.body` remains `None` because the body is multipart.

This structure supports a preference-based flow in application code, such as choosing HTML when appropriate and retaining plain text for another output. The README does not provide a ready-made helper that makes that policy decision. Selection remains application logic, and developers must account for parts that are neither of the two sample content types.

Release, dependency, and compatibility costs in Flanker 0.9.16

`setup.py` reports version `0.9.16`, while the release list dates that version to 2026-04-08. The repository is not archived, and its last push was on 2026-04-08. That is recent repository activity, but it does not resolve the project's documented Python 3 caution.

The base package depends on `attrs`, `chardet>=1.0.1`, `cryptography>=0.5`, `idna>=2.5`, `ply>=3.10`, `regex>=0.1.20110315`, `six`, `standard-imghdr==3.13.0`, `tld`, and `WebOb>=0.9.8`. The exact pin on `standard-imghdr` deserves attention during upgrades because it limits dependency freedom even though many other packages have lower bounds. Optional extras add validator dependencies, `cchardet>=0.3.5`, and the test dependencies.

The project is licensed under Apache-2.0, and `setup.py` declares `Apache 2`. That identifies the license, but it is not a substitute for reviewing notices and dependency licenses within a particular distribution. The repository includes `LICENSE`, `CHANGELOG.md`, `HACKING.md`, `tox.ini`, and separate user manual and API reference files, which provide documented locations for compatibility details and release changes that the quickstart does not summarize.

Editorial conclusion

Developers processing mailbox strings or MIME messages in Python can adopt Flanker when permissive parsing and Mailgun-oriented validation fit their code. Projects that require a modern Python support policy should first inspect Python 3 compatibility with their exact runtime and dependency versions. Flanker v0.9.16 is the documented release point to verify.

Frequently asked questions

How do I install mailgun/flanker?

The README documents `pip install flanker` or cloning the repository followed by `pip install -e .`. It says Python headers must be installed first.

Does mailgun/flanker support Python 3?

Python 3 support was added in v0.9.0, and `setup.py` includes Python 3 metadata. The README says the team knew tests passed with Python 3.6 but warns adopters to use Python 3 at their own risk.

How does mailgun/flanker validate email addresses?

The README says `validate_address()` combines parsing, DNS checks, MX existence checks, and ESP grammar checks. The validator dependencies are declared in the `validator` extra in `setup.py`.

Official sources

  1. License: Apache-2.0
  2. mailgun/flanker on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mailgun-flanker.svg)](https://hysenlabs.com/projects/mailgun-flanker)