Apache Airflow 邮件通知配置详解:SMTP 后端、Jinja 模板、Connection 凭据与 Provider 替代后端
2026/9/10 10:55:40 网站建设 项目流程

Apache Airflow 邮件通知配置详解:SMTP 后端、Jinja 模板、Connection 凭据与 Provider 替代后端

【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow

本篇基于 Apache Airflow 核心文档airflow-core/docs/howto/email-config.rst展开,系统讲解 Airflow 邮件通知体系的完整配置方式:如何选择与替换email_backend、如何用subject_template/html_content_template定制邮件标题与正文、如何通过smtp_defaultConnection 安全存放 SMTP 凭据,并结合源码 airflow-core/src/airflow/utils/email.py 剖析邮件发送的完整调用链、重试机制与 SSL 上下文处理,读完即可独立完成生产环境的邮件告警搭建。

一、[email] 配置段:选择邮件后端

Airflow 所有邮件(任务失败/重试回调、DAG 级邮件、send_email工具函数发出的邮件)统一走一个可插拔的后端机制。在airflow.cfg[email]段中设置email_backend

[email] email_backend = airflow.utils.email.send_email_smtp subject_template = /path/to/my_subject_template_file html_content_template = /path/to/my_html_content_template_file

等价的环境变量写法:

AIRFLOW__EMAIL__EMAIL_BACKEND=airflow.utils.email.send_email_smtp AIRFLOW__EMAIL__SUBJECT_TEMPLATE=/path/to/my_subject_template_file AIRFLOW__EMAIL__HTML_CONTENT_TEMPLATE=/path/to/my_html_content_template_file

从源码看,email_backend的默认值正是airflow.utils.email.send_email_smtp(通过 SMTP 发信),这一默认值定义在配置模板 airflow-core/src/airflow/config_templates/config.yml 中。

email_backend的本质是一个点分路径(dotted path):入口函数 send_email() 通过conf.getimport("email", "EMAIL_BACKEND")动态导入该路径指向的可调用对象并执行:

# airflow-core/src/airflow/utils/email.py 中的核心逻辑 backend = conf.getimport("email", "EMAIL_BACKEND") backend_conn_id = conn_id or conf.get("email", "EMAIL_CONN_ID") from_email = conf.get("email", "from_email", fallback=None) ... return backend(to_comma_separated, subject, html_content, files=files, dryrun=dryrun, cc=cc, bcc=bcc, ..., conn_id=backend_conn_id, from_email=from_email, ...)

从源码结构看,这意味着任何符合send_email(to, subject, html_content, ...)签名的函数都可以作为后端,包括社区 provider 提供的第三方 API 实现(见第六节)。

1.1 [email] 段完整参数一览

结合配置模板 airflow-core/src/airflow/config_templates/config.yml,[email]段可用选项及默认值如下:

配置项说明默认值
email_backend邮件后端函数的点分路径airflow.utils.email.send_email_smtp
email_conn_id用于存放凭据的 Connection IDsmtp_default
default_email_on_retry任务重试时是否发邮件告警True
default_email_on_failure任务失败时是否发邮件告警True
subject_template邮件标题的 Jinja2 模板文件路径(未设置时使用内置基础模板)
html_content_template邮件正文的 Jinja2 模板文件路径(未设置时使用内置基础模板)
from_email发件人地址,支持Sender Name <sender@email.com>格式
ssl_contextSMTP/IMAP SSL 连接使用的上下文:defaultnonedefault

二、用 Jinja2 模板定制邮件标题与正文

subject_templatehtml_content_template均为文件路径,文件内容使用Jinja2 模板语法渲染,模板中可以直接访问当前任务实例(Task Instance)的信息,例如try_numbermax_triesexception_htmlti.log_urlti.hostnameti.mark_success_url等。

官方文档给出的html_content_template示例文件内容如下:

Try {{try_number}} out of {{max_tries + 1}}<br> Exception:<br>{{exception_html}}<br> Log: <a href="{{ti.log_url}}">Link</a><br> Host: {{ti.hostname}}<br> Mark success: <a href="{{ti.mark_success_url}}">Link</a><br>

subject_template同样支持 Jinja2 变量,通常写成一个简短的单行文本(如[{{ dag.dag_id }}] Task failed: {{ ti.task_id }})。两个模板文件都未设置时,Airflow 使用内置的基础模板渲染标题与正文。

三、配置发件人地址 from_email

[email]段设置from_email指定发件人:

[email] from_email = "John Doe <johndoe@example.com>"

等价环境变量:

AIRFLOW__EMAIL__FROM_EMAIL="John Doe <johndoe@example.com>"

这里有一个容易被忽略的优先级细节。从 send_email_smtp() 源码看,mail_from的取值顺序是:

  1. 优先取[smtp] smtp_mail_from配置(默认airflow@example.com,见 config.yml);
  2. 若未设置则回退到from_email
  3. 两者都拿不到时抛出ValueError("You should set from email - ...")

也就是说smtp/smtp_mail_from的实际生效优先级高于email/from_email,调整发件人时建议同时检查两处配置,避免"改了 from_email 却没生效"的困惑。

四、SMTP 服务器参数:[smtp] 配置段

email_backend使用默认的send_email_smtp,SMTP 服务器参数只能从配置中读取(这一点源码中写得很明确:host、port 等一律来自conf,只有账号密码可来自 Connection)。[smtp]段完整参数及默认值(来自 config.yml):

配置项说明默认值
smtp_hostSMTP 服务器地址localhost
smtp_portSMTP 端口25
smtp_starttls连接后是否使用 STARTTLSTrue
smtp_ssl是否使用 SSL 隐式连接(SMTP_SSL)False
smtp_mail_from默认发件人地址airflow@example.com
smtp_timeout建立连接的超时时间(秒)30
smtp_retry_limit首次尝试后重试连接的次数5

对应的典型配置:

[smtp] smtp_host = smtp.example.com smtp_port = 587 smtp_starttls = True smtp_ssl = False smtp_mail_from = airflow@example.com smtp_timeout = 30 smtp_retry_limit = 5

源码 send_mime_email() 中的发送行为值得注意:

  • 重试机制:最多进行smtp_retry_limit + 1次尝试,捕获smtplib.SMTPServerDisconnected后继续重试,超出重试上限才向上抛出异常;
  • STARTTLS 上下文smtp_starttls为真时调用smtp_conn.starttls(context=_get_ssl_context()),而 _get_ssl_context() 根据email.ssl_context决定返回ssl.create_default_context()default,推荐)还是Nonenone,跳过证书校验——官方明确警告这会暴露于中间人攻击,只应在修复证书问题期间临时使用);
  • 连接方式smtp_ssl为真时创建smtplib.SMTP_SSL(465 端口常见),否则创建普通smtplib.SMTP

五、用 Connection 存放 SMTP 凭据:smtp_default

若不想把 SMTP 用户名/密码直接写进配置文件或环境变量,可以创建一个类型为Email的 Connection(默认 ID 为smtp_default),把凭据存在其中;也可以自选 Connection 名,并在[email]段用email_conn_id指定它。文档明确说明:该 Connection 可以是任意类型(例如 HTTP connection),[smtp]段的 host、port 等参数仍然只从配置读取。

源码印证了这一点。在 send_mime_email() 中:

smtp_user = None smtp_password = None if conn_id is not None: try: from airflow.models import Connection airflow_conn = Connection.get_connection_from_secrets(conn_id) smtp_user = airflow_conn.login smtp_password = airflow_conn.password except AirflowException: pass if smtp_user is None or smtp_password is None: log.debug("No user/password found for SMTP, so logging in with no authentication.")

即 Airflow 从 Connection 中只取login/password两个字段,取不到时降级为无认证登录(本地自建 SMTP 常见场景)。另外,conn_id的解析顺序是:调用方显式传入的conn_id参数 >email.email_conn_id配置(默认smtp_default),见 send_email()。

六、验证当前生效的邮件后端

配置完成后,可以用 CLI 直接查看当前生效的后端,确认配置没有写错位置:

$ airflow config get-value email email_backend airflow.utils.email.send_email_smtp

该命令返回的是综合了airflow.cfg与环境变量覆盖之后的最终生效值。关于配置项设置方式的更多说明,可参考 set-config 指南。

七、发送链路全貌:从 send_email 到 MIME 报文

把前几节串起来,Airflow 默认后端的完整调用链为:

  1. 入口:send_email() 解析email_backendemail_conn_id,将收件人归一化为逗号分隔字符串后调用后端函数;
  2. SMTP 后端:send_email_smtp() 按优先级确定mail_from,随后构建 MIME 报文;
  3. 构建报文:build_mime_message() 创建MIMEMultipart,写入Subject/From/To/Date头,正文以MIMEText(html_content, "html", ...)挂载;支持files参数附加文件(以MIMEApplication作为附件),CC 地址会出现在头字段并计入收件人列表,而BCC 只计入收件人、不出现在头字段中;还支持custom_headers注入任意自定义头;
  4. 投递:send_mime_email() 读取[smtp]段参数、从 Connection 取凭据,带重试地完成连接(可选 STARTTLS/SSL)、登录、sendmailquit

dryrun=True时第 4 步只记日志不真正发信,可用于开发环境联调。

八、替代邮件后端:通过 Provider 走第三方 API

除了 SMTP,email_backend还可以指向社区 provider 提供的实现,让邮件经由第三方服务的 API 发出。使用步骤(与原文档一致):

  1. 安装对应的 provider 发行包;
  2. email_backend设置为该 providersend_email函数的点分路径;
  3. email_conn_id设置为存放所需凭据的 Connection。

社区管理的 provider 所提供的邮件后端完整清单见 providers-summary-docs/core-extensions/email-backends.rst,该页面汇总了所有通过 community-managed providers 暴露的 email backend 实现。

由于send_email()的后端解析完全基于conf.getimport的通用导入机制(从源码结构看),provider 后端只要遵循相同的函数签名即可无缝替换,无需改动任何 Airflow 核心代码。

九、小结:一份可落地的最小配置

综合以上各节,一个生产可用的最小配置示例:

[email] email_backend = airflow.utils.email.send_email_smtp email_conn_id = smtp_default subject_template = /opt/airflow/templates/email_subject.jinja2 html_content_template = /opt/airflow/templates/email_body.jinja2 from_email = "Airflow Alert <alert@example.com>" ssl_context = default [smtp] smtp_host = smtp.example.com smtp_port = 587 smtp_starttls = True smtp_ssl = False smtp_mail_from = alert@example.com smtp_timeout = 30 smtp_retry_limit = 5

再配合 UI 中创建的smtp_defaultConnection(凭据)与两个 Jinja2 模板文件,即可完成 Airflow 的邮件告警体系;default_email_on_retrydefault_email_on_failure默认均为True,任务重试与失败通知开箱即用。

【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询