You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ep...@apache.org on 2023/01/11 21:26:06 UTC
[airflow] 25/27: Add doc-strings and small improvement to email util (#28634)
This is an automated email from the ASF dual-hosted git repository.
ephraimanierobi pushed a commit to branch v2-5-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 7c346b553a373b53b67fa68ec4426c9d5fccce50
Author: Stanislav Kazanov <94...@users.noreply.github.com>
AuthorDate: Thu Dec 29 21:37:48 2022 +0300
Add doc-strings and small improvement to email util (#28634)
(cherry picked from commit 906264dd904a8f44a1533ffb70ec0cd6b9f92a4b)
---
airflow/utils/email.py | 123 ++++++++++++++++++++++++++++++++++++-------------
1 file changed, 90 insertions(+), 33 deletions(-)
diff --git a/airflow/utils/email.py b/airflow/utils/email.py
index 67c6a90b26..ee570399e7 100644
--- a/airflow/utils/email.py
+++ b/airflow/utils/email.py
@@ -20,6 +20,7 @@ from __future__ import annotations
import collections.abc
import logging
import os
+import re
import smtplib
import warnings
from email.mime.application import MIMEApplication
@@ -47,8 +48,26 @@ def send_email(
conn_id: str | None = None,
custom_headers: dict[str, Any] | None = None,
**kwargs,
-):
- """Send email using backend specified in EMAIL_BACKEND."""
+) -> None:
+ """
+ Send an email using the backend specified in the *EMAIL_BACKEND* configuration option.
+
+ :param to: A list or iterable of email addresses to send the email to.
+ :param subject: The subject of the email.
+ :param html_content: The content of the email in HTML format.
+ :param files: A list of paths to files to attach to the email.
+ :param dryrun: If *True*, the email will not actually be sent. Default: *False*.
+ :param cc: A string or iterable of strings containing email addresses to send a copy of the email to.
+ :param bcc: A string or iterable of strings containing email addresses to send a
+ blind carbon copy of the email to.
+ :param mime_subtype: The subtype of the MIME message. Default: "mixed".
+ :param mime_charset: The charset of the email. Default: "utf-8".
+ :param conn_id: The connection ID to use for the backend. If not provided, the default connection
+ specified in the *EMAIL_CONN_ID* configuration option will be used.
+ :param custom_headers: A dictionary of additional headers to add to the MIME message.
+ No validations are run on these values, and they should be able to be encoded.
+ :param kwargs: Additional keyword arguments to pass to the 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)
@@ -87,9 +106,22 @@ def send_email_smtp(
from_email: str | None = None,
custom_headers: dict[str, Any] | None = None,
**kwargs,
-):
- """
- Send an email with html content
+) -> None:
+ """Send an email with html content.
+
+ :param to: Recipient email address or list of addresses.
+ :param subject: Email subject.
+ :param html_content: Email body in HTML format.
+ :param files: List of file paths to attach to the email.
+ :param dryrun: If True, the email will not be sent, but all other actions will be performed.
+ :param cc: Carbon copy recipient email address or list of addresses.
+ :param bcc: Blind carbon copy recipient email address or list of addresses.
+ :param mime_subtype: MIME subtype of the email.
+ :param mime_charset: MIME charset of the email.
+ :param conn_id: Connection ID of the SMTP server.
+ :param from_email: Sender email address.
+ :param custom_headers: Dictionary of custom headers to include in the email.
+ :param kwargs: Additional keyword arguments.
>>> send_email('test@example.com', 'foo', '<b>Foo</b> bar', ['/dev/null'], dryrun=True)
"""
@@ -133,21 +165,20 @@ def build_mime_message(
custom_headers: dict[str, Any] | None = None,
) -> tuple[MIMEMultipart, list[str]]:
"""
- Build a MIME message that can be used to send an email and
- returns full list of recipients.
-
- :param mail_from: Email address to set as email's from
- :param to: List of email addresses to set as email's to
- :param subject: Email's subject
- :param html_content: Content of email in HTML format
- :param files: List of paths of files to be attached
- :param cc: List of email addresses to set as email's CC
- :param bcc: List of email addresses to set as email's BCC
- :param mime_subtype: Can be used to specify the subtype of the message. Default = mixed
- :param mime_charset: Email's charset. Default = UTF-8.
- :param custom_headers: Additional headers to add to the MIME message.
- No validations are run on these values and they should be able to be encoded.
- :return: Email as MIMEMultipart and list of recipients' addresses.
+ Build a MIME message that can be used to send an email and returns a full list of recipients.
+
+ :param mail_from: Email address to set as the email's "From" field.
+ :param to: A string or iterable of strings containing email addresses to set as the email's "To" field.
+ :param subject: The subject of the email.
+ :param html_content: The content of the email in HTML format.
+ :param files: A list of paths to files to be attached to the email.
+ :param cc: A string or iterable of strings containing email addresses to set as the email's "CC" field.
+ :param bcc: A string or iterable of strings containing email addresses to set as the email's "BCC" field.
+ :param mime_subtype: The subtype of the MIME message. Default: "mixed".
+ :param mime_charset: The charset of the email. Default: "utf-8".
+ :param custom_headers: Additional headers to add to the MIME message. No validations are run on these
+ values, and they should be able to be encoded.
+ :return: A tuple containing the email as a MIMEMultipart object and a list of recipient email addresses.
"""
to = get_email_address_list(to)
@@ -159,12 +190,12 @@ def build_mime_message(
if cc:
cc = get_email_address_list(cc)
msg["CC"] = ", ".join(cc)
- recipients = recipients + cc
+ recipients += cc
if bcc:
# don't add bcc in header
bcc = get_email_address_list(bcc)
- recipients = recipients + bcc
+ recipients += bcc
msg["Date"] = formatdate(localtime=True)
mime_text = MIMEText(html_content, "html", mime_charset)
@@ -192,7 +223,15 @@ def send_mime_email(
conn_id: str = "smtp_default",
dryrun: bool = False,
) -> None:
- """Send MIME email."""
+ """
+ Send a MIME email.
+
+ :param e_from: The email address of the sender.
+ :param e_to: The email address or a list of email addresses of the recipient(s).
+ :param mime_msg: The MIME message to send.
+ :param conn_id: The ID of the SMTP connection to use.
+ :param dryrun: If True, the email will not be sent, but a log message will be generated.
+ """
smtp_host = conf.get_mandatory_value("smtp", "SMTP_HOST")
smtp_port = conf.getint("smtp", "SMTP_PORT")
smtp_starttls = conf.getboolean("smtp", "SMTP_STARTTLS")
@@ -245,20 +284,33 @@ def send_mime_email(
def get_email_address_list(addresses: str | Iterable[str]) -> list[str]:
- """Get list of email addresses."""
+ """
+ Returns a list of email addresses from the provided input.
+
+ :param addresses: A string or iterable of strings containing email addresses.
+ :return: A list of email addresses.
+ :raises TypeError: If the input is not a string or iterable of strings.
+ """
if isinstance(addresses, str):
return _get_email_list_from_str(addresses)
-
elif isinstance(addresses, collections.abc.Iterable):
if not all(isinstance(item, str) for item in addresses):
raise TypeError("The items in your iterable must be strings.")
return list(addresses)
-
- received_type = type(addresses).__name__
- raise TypeError(f"Unexpected argument type: Received '{received_type}'.")
+ else:
+ raise TypeError(f"Unexpected argument type: Received '{type(addresses).__name__}'.")
def _get_smtp_connection(host: str, port: int, timeout: int, with_ssl: bool) -> smtplib.SMTP:
+ """
+ Returns an SMTP connection to the specified host and port, with optional SSL encryption.
+
+ :param host: The hostname or IP address of the SMTP server.
+ :param port: The port number to connect to on the SMTP server.
+ :param timeout: The timeout in seconds for the connection.
+ :param with_ssl: Whether to use SSL encryption for the connection.
+ :return: An SMTP connection to the specified host and port.
+ """
return (
smtplib.SMTP_SSL(host=host, port=port, timeout=timeout)
if with_ssl
@@ -267,8 +319,13 @@ def _get_smtp_connection(host: str, port: int, timeout: int, with_ssl: bool) ->
def _get_email_list_from_str(addresses: str) -> list[str]:
- delimiters = [",", ";"]
- for delimiter in delimiters:
- if delimiter in addresses:
- return [address.strip() for address in addresses.split(delimiter)]
- return [addresses]
+ """
+ Extract a list of email addresses from a string. The string
+ can contain multiple email addresses separated by
+ any of the following delimiters: ',' or ';'.
+
+ :param addresses: A string containing one or more email addresses.
+ :return: A list of email addresses.
+ """
+ pattern = r"\s*[,;]\s*"
+ return [address for address in re.split(pattern, addresses)]