Mailtrap Airflow Provider
An Apache Airflow provider for Mailtrap.io - send transactional emails from your Airflow DAGs.
Installation
pip install airflow-provider-mailtrap
Requirements
- Python >= 3.9
- Apache Airflow >= 2.4
- Mailtrap API token (get one here)
Setup
1. Create a Mailtrap Connection
In the Airflow UI, go to Admin → Connections → Add:
| Field | Value |
|---|---|
| Connection Id | mailtrap_default |
| Connection Type | mailtrap |
| Password | Your Mailtrap API token |
| Extra (optional) | {"sender": "noreply@yourdomain.com", "sender_name": "Your App"} |
2. Use the Operator in Your DAG
from mailtrap_provider.operators.send_email import MailtrapSendEmailOperator
send_email = MailtrapSendEmailOperator(
task_id="send_welcome_email",
to="user@example.com",
subject="Welcome!",
html="<h1>Welcome to our service!</h1>",
sender="noreply@yourdomain.com",
sender_name="My App",
)
Usage Examples
Send a Plain Text Email
from mailtrap_provider.operators.send_email import MailtrapSendEmailOperator
send_notification = MailtrapSendEmailOperator(
task_id="send_notification",
to="user@example.com",
subject="Task Completed",
text="Your workflow has completed successfully.",
sender="notifications@yourdomain.com",
)
Send an HTML Email
send_report = MailtrapSendEmailOperator(
task_id="send_report",
to="team@example.com",
subject="Daily Report",
html="""
<html>
<body>
<h1>Daily Report</h1>
<p>Here is your daily summary...</p>
</body>
</html>
""",
sender="reports@yourdomain.com",
sender_name="Report Bot",
category="daily-reports", # For Mailtrap analytics
)
Send to Multiple Recipients
send_to_team = MailtrapSendEmailOperator(
task_id="notify_team",
to=["alice@example.com", "bob@example.com"],
subject="Team Update",
text="Important update for the team.",
sender="noreply@yourdomain.com",
)
Use Templated Fields
All parameters are templatable, so you can use Jinja templates:
send_dynamic_email = MailtrapSendEmailOperator(
task_id="send_dynamic_email",
to="{{ var.value.recipient_email }}",
subject="Report for {{ ds }}",
text="Data processed: {{ ti.xcom_pull(task_ids='process_data') }}",
sender="{{ var.value.sender_email }}",
)
Operator Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
to |
str | list[str] |
✅ | Recipient email address(es) |
subject |
str |
✅ | Email subject line |
text |
str |
⚠️ | Plain text body (required if no html) |
html |
str |
⚠️ | HTML body (required if no text) |
sender |
str |
⚠️ | Sender email (falls back to connection extra) |
sender_name |
str |
❌ | Display name for sender |
category |
str |
❌ | Category for Mailtrap analytics |
mailtrap_conn_id |
str |
❌ | Connection ID (default: mailtrap_default) |
Using the Hook Directly
For more advanced use cases, you can use the hook directly:
from mailtrap_provider.hooks.mailtrap import MailtrapHook
# Simple usage with the helper method
hook = MailtrapHook()
response = hook.send_email(
sender="sender@example.com",
to="recipient@example.com",
subject="Hello",
text="Hello from Airflow!",
)
# Advanced usage with raw client
client = hook.get_conn() # Returns mailtrap.MailtrapClient
# Use client directly for advanced features
Connection Extras
You can store default sender information in the connection extras:
{
"sender": "noreply@yourdomain.com",
"sender_name": "Your Application"
}
When sender is not provided to the operator, it will use the value from connection extras.
Development
Setup Development Environment
# Install Astro CLI (macOS)
brew install astro
# Setup dev environment
./scripts/setup-dev.sh
# Start local Airflow
cd dev && astro dev start
Access Airflow UI at http://localhost:8080 (user: admin, pass: admin)
Note: The setup script enables
AIRFLOW__CORE__TEST_CONNECTION=Enabledso the "Test" button works in the connection form. This is disabled by default in Airflow for security.
After Code Changes
./scripts/sync-provider.sh
Run Tests
pip install pytest requests-mock
pytest tests/ -v
License
Apache License 2.0 - see LICENSE for details.
Links
Metadata
Release files for airflow-provider-mailtrap 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| airflow_provider_mailtrap-1.0.0.tar.gz | 14.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| airflow_provider_mailtrap-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.1 kB
Release files / airflow_provider_mailtrap-1.0.0.tar.gz
| Download URL | airflow_provider_mailtrap-1.0.0.tar.gz |
|---|---|
| Size | 14.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c0abe727b98272f915f30640b6847854f7bc7f3c5f8c096aabf12795d649eac0
|
|
BLAKE2b-256 checksum How to use checksums |
1be47856d03baef8d6422c85bbce1076a0a00e84bff5ba689b023ca0a0f047f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 28, 2026.
Transparency logRelease files / airflow_provider_mailtrap-1.0.0-py3-none-any.whl
| Download URL | airflow_provider_mailtrap-1.0.0-py3-none-any.whl |
|---|---|
| Size | 17.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8df1a4caaecb2a15774227bc2f99be05d4c0a46e7a8d45e79faf62e4bbe973d3
|
|
BLAKE2b-256 checksum How to use checksums |
cdaa2c8dd758d933ed252e282252bdfbdc66bd487a91754a6ba1405a07227d42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 28, 2026.
Transparency log