Skip to content

Fix SMTP connection from_email being ignored by email_on_failure and … - #69271

Open
bramhanandlingala wants to merge 8 commits into
apache:mainfrom
bramhanandlingala:fix/#69262
Open

Fix SMTP connection from_email being ignored by email_on_failure and …#69271
bramhanandlingala wants to merge 8 commits into
apache:mainfrom
bramhanandlingala:fix/#69262

Conversation

@bramhanandlingala

@bramhanandlingalabramhanandlingala commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

_send_error_email_notification (used for email_on_failure / email_on_retry) resolved [email] from_email before constructing SmtpNotifier, so SmtpNotifier's own connection-extra fallback branch never ran. This meant the SMTP connection's from_email extra was silently ignored whenever [email] from_email was set — or even when it wasn't, since a hardcoded airflow@airflow fallback was passed in regardless.

This PR moves from_email precedence resolution into SmtpNotifier itself:

  1. Explicit from_email argument (if passed directly to SmtpNotifier)
  2. SMTP connection extra from_email
  3. [email] from_email config
  4. Hardcoded airflow@airflow default

task_runner.py now passes from_email=None to SmtpNotifier and lets it resolve precedence, instead of resolving [email] from_email upfront and locking out the connection-extra check.

Root cause

# before (task_runner.py)from_email=conf.get("email", "from_email", fallback="airflow@airflow"),

Since this was never None, SmtpNotifier._build_email_content's if self.from_email is None: branch — which checks the SMTP connection's from_email extra — could never execute.

Fix

  • providers/smtp/src/airflow/providers/smtp/notifications/smtp.py: _build_email_content now falls back through connection extra → [email] from_email config → hardcoded default, instead of raising when the connection extra is unset.
  • task-sdk/src/airflow/sdk/execution_time/task_runner.py: passes from_email=None so the notifier's own resolution logic runs.

Testing

  • Added 3 new unit tests in test_smtp.py covering all precedence combinations (connection-only, config-only, connection-over-config, neither-set-default).
  • Updated 3 existing assertions in test_task_runner.py to reflect that from_email resolution now happens inside SmtpNotifier, not task_runner.py.

Fixes#69262

Gen-AI disclosure: I used a generative AI tool to help identify the root
cause, write tests, and draft the PR description. I reviewed, tested, and
verified all changes locally before submitting.

Was generative AI tooling used to co-author this PR?
  • Yes — Claude

Generated-by: Claude following the guidelines

@SameerMesiah97SameerMesiah97 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one clarification. Looks good otherwise.

@@ -2058,50 +1951,13 @@ def _send_error_email_notification(
to=to_emails,
subject=subject,
html_content=html_content,
from_email=conf.get("email", "from_email", fallback="airflow@airflow"),
from_email=None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any other callers that still resolve from_email themselves before constructing the notifier? Please check.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @SameerMesiah97

Good question — I checked. SmtpNotifier is only constructed in one production call site outside its own module, which is _send_error_email_notification in task_runner.py, and that's already updated in this PR to pass from_email=None. I didn't find any other operator or utility in the repo that resolves from_email from config before building the notifier, so this should cover all callers.

@stephsi

Copy link
Copy Markdown
Contributor

Hello @bramhanandlingala!

Thanks for creating a PR related to my issue. I think your suggested changes make sense overall.

I have one suggestion though:
Your three test cases now cover config-only, connection-over-config and neither-set-default , I would argue that you should also adjust the already existing test case connection-only to the style of your three created test cases, so it is more clear that these four test cases belong together. Also add a comment at the beginning to the already existing test case similar to your three test cases.

I also have some wording suggestions for the test comments, but these are maybe more personal preferences.

@@ -211,6 +211,70 @@ def test_notifier_with_nondefault_connection_extra(
**DEFAULT_EMAIL_PARAMS,
)

@mock.patch("airflow.providers.smtp.notifications.smtp.SmtpHook")
def test_notifier_from_email_falls_back_to_config(self, mock_smtphook_hook, create_dag_without_db):
"""When from_email is unset and the connection defines none, `[email] from_email` config is used."""

@stephsistephsiJul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""When from_email is unset and the connection defines none, `[email] from_email` config is used."""
"""When config [email] from_email is set and the SMTP connection extra `from_email` is NOT set, `[email] from_email` config is used."""

I assume unset was a typing mistake as this is the test case where the config is set and the connection extra field is not set.

@bramhanandlingala

Copy link
Copy Markdown
ContributorAuthor

Hi @stephsi

Good catch, thanks — that was indeed a typo, "unset" should've said the connection extra is not set. Fixed in the latest commit using your suggested wording exactly. I've also added a matching docstring to test_notifier_with_nondefault_connection_extra so all four tests (connection-only, config-only, connection-over-config, neither-set-default) are now consistent in style, per your other comment. Happy to take any further wording suggestions if you have them.

@potiukpotiuk added the ready for maintainer review Set after triaging when all criteria pass. label Jul 18, 2026
@bramhanandlingala

bramhanandlingala commented Jul 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Hi @stephsi

Could you please review the code and approve the PR

@shahar1shahar1 added pending-response and removed ready for maintainer review Set after triaging when all criteria pass. labels Jul 25, 2026

@shahar1shahar1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@potiukpotiuk added the ready for maintainer review Set after triaging when all criteria pass. label Jul 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because the author has not responded to a request for more information. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

@github-actionsgithub-actionsBot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:providersarea:task-sdkpending-responseprovider:smtpready for maintainer reviewSet after triaging when all criteria pass.staleStale PRs per the .github/workflows/stale.yml policy file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SMTP connection configuration from_email is ignored by email_on_failure and email_on_retry

5 participants

@bramhanandlingala@stephsi@shahar1@SameerMesiah97@potiuk