SMTP Connection¶
The SMTP connection type enables integrations such as
SmtpHook
.
Note
The legacy helper in airflow.utils.email
is scheduled for deprecation
and will be removed in a future major release.
Please migrate to SmtpHook
or other provider-level utilities for sending emails.
Default Connection ID¶
The default ID is smtp_default
when no conn_id
is supplied.
Authenticating to SMTP¶
Two methods are supported:
Basic – traditional username + password.
OAuth 2 / XOAUTH2 – bearer-token based, required by Gmail API, Microsoft 365 / Outlook.com and other modern providers.
If you omit credentials the hook attempts an anonymous session, accepted only by open-relay test servers.
Configuring the Connection¶
- Login
Username (for example
user@example.com
).- Password
Password or app-specific password. Ignored when
auth_type="oauth2"
.- Host
SMTP server hostname (for example
smtp.gmail.com
).- Port
Port number. Defaults to 465 when SSL is enabled, otherwise 587.
- Extra (optional – JSON)
Additional parameters.
General
from_email
– Default From: address.disable_ssl
(bool) – Disable SSL/TLS entirely. Defaultfalse
.disable_tls
(bool) – SkipSTARTTLS
. Defaultfalse
.timeout
(int) – Socket timeout (seconds). Default30
.retry_limit
(int) – Connection attempts before raising. Default5
.ssl_context
–"default"
|"none"
See SSL / TLS Notes.
Templating
subject_template
– File path for custom subject.html_content_template
– File path for custom HTML body.
Authentication
auth_type
–"basic"
(default) |"oauth2"
access_token
– OAuth 2 bearer (one-hour).client_id
/client_secret
– Credentials for token refresh. (auto-defaults to Google or Microsoft).tenant_id
– Azure tenant (default"common"
).scope
– OAuth scopeGmail:
https://mail.google.com/
Outlook (Graph):
https://outlook.office.com/.default
SSL / TLS Notes¶
ssl_context="default"
– reasonable trust store & secure ciphers (recommended)ssl_context="none"
– disables certificate validation; use only for local testing with self-signed certificates.
Examples¶
Basic Auth — SendGrid (STARTTLS 587)¶
export AIRFLOW_CONN_SMTP_SENDGRID='smtp://apikey:SG.YOUR_API_KEY@smtp.sendgrid.net:587?\
disable_ssl=true&\
from_email=you%40example.com'
OAuth 2 — Gmail (access token, STARTTLS 587)¶
export AIRFLOW_CONN_SMTP_GMAIL='smtp://your.name%40gmail.com@smtp.gmail.com:587?\
auth_type=oauth2&\
access_token=ya29.<URL_ENCODED_TOKEN>&\
from_email=your.name%40gmail.com&\
disable_ssl=true'
OAuth 2 — Gmail (SSL 465)¶
export AIRFLOW_CONN_SMTP_GMAIL_SSL='smtp://your.name%40gmail.com@smtp.gmail.com:465?\
auth_type=oauth2&\
access_token=ya29.<URL_ENCODED_TOKEN>&\
from_email=your.name%40gmail.com&\
disable_tls=true'
OAuth 2 — Microsoft 365 (client credentials 587)¶
export AIRFLOW_CONN_SMTP_M365='smtp://user%40contoso.com@smtp.office365.com:587?\
auth_type=oauth2&\
client_id=YOUR_APP_ID&\
client_secret=YOUR_SECRET&\
tenant_id=YOUR_TENANT_ID&\
scope=https%3A%2F%2Foutlook.office.com%2F.default&\
disable_ssl=true'
OAuth2 — Microsoft 365 (client-credential flow)¶
export AIRFLOW_CONN_SMTP_M365='smtp://user@contoso.com@smtp.office365.com:587?\
auth_type=oauth2&\
client_id=YOUR_APP_ID&\
client_secret=YOUR_SECRET&\
tenant_id=YOUR_TENANT_ID&\
scope=https%3A%2F%2Foutlook.office.com%2F.default'
Troubleshooting¶
Error message |
Likely cause |
Fix |
---|---|---|
|
Port 587 but the connection starts with SSL (no STARTTLS). |
Add |
|
Port 465 yet the hook still issues |
Add |
|
Access-token expired or missing the |
Generate a fresh token. |
|
Sender identity not verified at the provider or |
Verify the sender / domain and ensure |
Programmatic creation¶
from airflow.models.connection import Connection
conn = Connection(
conn_id="smtp_gmail_token",
conn_type="smtp",
host="smtp.gmail.com",
login="me@gmail.com",
extra={"auth_type": "oauth2", "access_token": "ya29.a0AfB..."},
)
print(conn.test_connection())
URI encoding¶
When creating connections programmatically or via the CLI, ensure that
When fields contain special characters (/
, @
, :
…), URL-encode them,
for example via
airflow.models.connection.Connection.get_uri()
.
CLI creation (Gmail OAuth 2)¶
Prefer environment variables for portability, but you can also create the connection via CLI:
airflow connections add smtp_gmail_oauth2 \
--conn-type smtp \
--conn-host smtp.gmail.com \
--conn-port 587 \
--conn-login '<YOUR_EMAIL>@gmail.com' \
--conn-extra '{
"from_email": "<YOUR_EMAIL>@gmail.com",
"auth_type": "oauth2",
"access_token": "<YOUR_OAUTH2_ACCESS_TOKEN>",
"disable_ssl": "true"
}'
Note
The [smtp]
section in airflow.cfg
is used by the core
e-mail helper slated for deprecation.
When you switch to SmtpHook
and supply a smtp_conn_id
, the hook’s connection settings take
precedence and the global [smtp]
options may be ignored.
Using SmtpHook
in a DAG¶
1from datetime import datetime
2
3from airflow import DAG
4from airflow.operators.python import PythonOperator
5from airflow.providers.smtp.hooks.smtp import SmtpHook
6
7
8def gmail_oauth2_test():
9 with SmtpHook(smtp_conn_id="smtp_gmail_oauth2") as hook:
10 hook.send_email_smtp(
11 to="recipient@example.com",
12 subject="[Airflow→Gmail] OAuth2 OK",
13 html_content="<h3>Gmail XOAUTH2 works 🎉</h3>",
14 )
15
16
17with DAG(
18 dag_id="test_gmail_oauth2",
19 start_date=datetime(2025, 7, 1),
20 schedule=None,
21 catchup=False,
22 tags=["example"],
23) as dag:
24 PythonOperator(
25 task_id="send_mail",
26 python_callable=gmail_oauth2_test,
27 )
See also
Google OAuth 2.0 for Gmail – https://developers.google.com/identity/protocols/oauth2
Microsoft Graph OAuth 2.0 – https://learn.microsoft.com/graph/auth/