This is an automated email from the ASF dual-hosted git repository. jedcunningham pushed a commit to branch v2-2-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit fd5558fe9eb4c82f1aa49244deb75a6d500334bc Author: ignaski <[email protected]> AuthorDate: Fri Oct 29 12:10:49 2021 +0300 Fixing ses email backend (#18042) (cherry picked from commit 1543dc28f4a2f1631dfaedd948e646a181ccf7ee) --- airflow/config_templates/config.yml | 8 +++++ airflow/config_templates/default_airflow.cfg | 5 +++ airflow/providers/amazon/aws/utils/emailer.py | 3 +- airflow/utils/email.py | 10 ++++-- docs/apache-airflow/howto/email-config.rst | 7 ++++ tests/providers/amazon/aws/utils/test_emailer.py | 42 +++++++++++++----------- tests/utils/test_email.py | 14 ++++++++ 7 files changed, 66 insertions(+), 23 deletions(-) diff --git a/airflow/config_templates/config.yml b/airflow/config_templates/config.yml index 6fa38d7..a70854e 100644 --- a/airflow/config_templates/config.yml +++ b/airflow/config_templates/config.yml @@ -1353,6 +1353,14 @@ example: "/path/to/my_html_content_template_file" default: ~ see_also: ":doc:`Email Configuration </howto/email-config>`" + - name: from_email + description: | + Email address that will be used as sender address. + It can either be raw email or the complete address in a format ``Sender Name <[email protected]>`` + version_added: 2.3.0 + type: string + example: "Airflow <[email protected]>" + default: ~ - name: smtp description: | diff --git a/airflow/config_templates/default_airflow.cfg b/airflow/config_templates/default_airflow.cfg index 7124d95..6a5449b 100644 --- a/airflow/config_templates/default_airflow.cfg +++ b/airflow/config_templates/default_airflow.cfg @@ -681,6 +681,11 @@ default_email_on_failure = True # Example: html_content_template = /path/to/my_html_content_template_file # html_content_template = +# Email address that will be used as sender address. +# It can either be raw email or the complete address in a format ``Sender Name <[email protected]>`` +# Example: from_email = Airflow <[email protected]> +# from_email = + [smtp] # If you want airflow to send emails on retries, failure, and you want to use diff --git a/airflow/providers/amazon/aws/utils/emailer.py b/airflow/providers/amazon/aws/utils/emailer.py index d098892..fc34835 100644 --- a/airflow/providers/amazon/aws/utils/emailer.py +++ b/airflow/providers/amazon/aws/utils/emailer.py @@ -23,6 +23,7 @@ from airflow.providers.amazon.aws.hooks.ses import SESHook def send_email( + from_email: str, to: Union[List[str], str], subject: str, html_content: str, @@ -37,7 +38,7 @@ def send_email( """Email backend for SES.""" hook = SESHook(aws_conn_id=conn_id) hook.send_email( - mail_from=None, + mail_from=from_email, to=to, subject=subject, html_content=html_content, diff --git a/airflow/utils/email.py b/airflow/utils/email.py index 7d17027..50f2415 100644 --- a/airflow/utils/email.py +++ b/airflow/utils/email.py @@ -49,6 +49,8 @@ def send_email( """Send email using backend specified in EMAIL_BACKEND.""" 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) + to_list = get_email_address_list(to) to_comma_separated = ", ".join(to_list) @@ -63,6 +65,7 @@ def send_email( mime_subtype=mime_subtype, mime_charset=mime_charset, conn_id=backend_conn_id, + from_email=from_email, **kwargs, ) @@ -78,6 +81,7 @@ def send_email_smtp( mime_subtype: str = 'mixed', mime_charset: str = 'utf-8', conn_id: str = "smtp_default", + from_email: str = None, **kwargs, ): """ @@ -87,8 +91,10 @@ def send_email_smtp( """ smtp_mail_from = conf.get('smtp', 'SMTP_MAIL_FROM') + mail_from = smtp_mail_from or from_email + msg, recipients = build_mime_message( - mail_from=smtp_mail_from, + mail_from=mail_from, to=to, subject=subject, html_content=html_content, @@ -99,7 +105,7 @@ def send_email_smtp( mime_charset=mime_charset, ) - send_mime_email(e_from=smtp_mail_from, e_to=recipients, mime_msg=msg, conn_id=conn_id, dryrun=dryrun) + send_mime_email(e_from=mail_from, e_to=recipients, mime_msg=msg, conn_id=conn_id, dryrun=dryrun) def build_mime_message( diff --git a/docs/apache-airflow/howto/email-config.rst b/docs/apache-airflow/howto/email-config.rst index 67e26a7..af7b3cf 100644 --- a/docs/apache-airflow/howto/email-config.rst +++ b/docs/apache-airflow/howto/email-config.rst @@ -29,6 +29,8 @@ in the ``[email]`` section. subject_template = /path/to/my_subject_template_file html_content_template = /path/to/my_html_content_template_file +You can configure sender's email address by setting ``from_email`` in the ``[email]`` section. + To configure SMTP settings, checkout the :ref:`SMTP <config:smtp>` section in the standard configuration. If you do not want to store the SMTP credentials in the config or in the environment variables, you can create a connection called ``smtp_default`` of ``Email`` type, or choose a custom connection name and set the ``email_conn_id`` with it's name in @@ -91,6 +93,9 @@ or name and set it in ``email_conn_id`` of 'Email' type. Only login and password are used from the connection. +4. Configure sender's email address and name either by exporting the environment variables ``SENDGRID_MAIL_FROM`` and ``SENDGRID_MAIL_SENDER`` or + in your ``airflow.cfg`` by setting ``from_email`` in the ``[email]`` section. + .. _email-configuration-ses: Send email using AWS SES @@ -116,3 +121,5 @@ Follow the steps below to enable it: 3. Create a connection called ``aws_default``, or choose a custom connection name and set it in ``email_conn_id``. The type of connection should be ``Amazon Web Services``. + +4. Configure sender's email address in your ``airflow.cfg`` by setting ``from_email`` in the ``[email]`` section. diff --git a/tests/providers/amazon/aws/utils/test_emailer.py b/tests/providers/amazon/aws/utils/test_emailer.py index 3d99573..bcbbd4e 100644 --- a/tests/providers/amazon/aws/utils/test_emailer.py +++ b/tests/providers/amazon/aws/utils/test_emailer.py @@ -16,27 +16,29 @@ # specific language governing permissions and limitations # under the License. # - -from unittest import mock +from unittest import TestCase, mock from airflow.providers.amazon.aws.utils.emailer import send_email [email protected]("airflow.providers.amazon.aws.utils.emailer.SESHook") -def test_send_email(mock_hook): - send_email( - to="[email protected]", - subject="subject", - html_content="content", - ) - mock_hook.return_value.send_email.assert_called_once_with( - mail_from=None, - to="[email protected]", - subject="subject", - html_content="content", - bcc=None, - cc=None, - files=None, - mime_charset="utf-8", - mime_subtype="mixed", - ) +class TestSendEmailSes(TestCase): + @mock.patch("airflow.providers.amazon.aws.utils.emailer.SESHook") + def test_send_ses_email(self, mock_hook): + send_email( + from_email="From Test <[email protected]>", + to="[email protected]", + subject="subject", + html_content="content", + ) + + mock_hook.return_value.send_email.assert_called_once_with( + mail_from="From Test <[email protected]>", + to="[email protected]", + subject="subject", + html_content="content", + bcc=None, + cc=None, + files=None, + mime_charset="utf-8", + mime_subtype="mixed", + ) diff --git a/tests/utils/test_email.py b/tests/utils/test_email.py index 28d4328..b458bbd 100644 --- a/tests/utils/test_email.py +++ b/tests/utils/test_email.py @@ -99,9 +99,23 @@ class TestEmail(unittest.TestCase): mime_charset='utf-8', mime_subtype='mixed', conn_id='smtp_default', + from_email=None, ) assert not mock_send_email.called + @mock.patch('airflow.utils.email.send_email_smtp') + @conf_vars( + { + ('email', 'email_backend'): 'tests.utils.test_email.send_email_test', + ('email', 'from_email'): '[email protected]', + } + ) + def test_custom_backend_sender(self, mock_send_email_smtp): + utils.email.send_email('to', 'subject', 'content') + _, call_kwargs = send_email_test.call_args + assert call_kwargs['from_email'] == '[email protected]' + assert not mock_send_email_smtp.called + def test_build_mime_message(self): mail_from = '[email protected]' mail_to = '[email protected]'
