diff options
| author | Mike Edmunds <medmunds@gmail.com> | 2026-04-07 14:18:09 -0700 |
|---|---|---|
| committer | nessita <124304+nessita@users.noreply.github.com> | 2026-04-16 15:39:03 -0300 |
| commit | 8bb01b1b11ee771dedf30c6ff9452a1699810016 (patch) | |
| tree | c5cfa6bcaf7e45be0a77360dc9d489f7de2b6cdb /docs/topics | |
| parent | 5a79a092af43ad59220e2237cd5f90f6d628deab (diff) | |
Refs #35514 -- Moved and renamed "Sending multiple emails" in email docs.
Moved "Sending multiple emails" from the "Email backends" section to the
"Sending messages" section and renamed it to "Sending many messages
efficiently" to better reflect its content.
Moved the related connection manager example from the "Email backends"
intro into the same section.
Diffstat (limited to 'docs/topics')
| -rw-r--r-- | docs/topics/email.txt | 195 |
1 files changed, 102 insertions, 93 deletions
diff --git a/docs/topics/email.txt b/docs/topics/email.txt index 36f7b71e97..0af0bf073d 100644 --- a/docs/topics/email.txt +++ b/docs/topics/email.txt @@ -649,6 +649,106 @@ to "/contact/thanks/" when it's done:: .. _Header injection: http://www.nyphp.org/phundamentals/8_Preventing-Email-Header-Injection.html +.. _topics-sending-multiple-emails: + +Sending many messages efficiently +--------------------------------- + +Establishing and closing an SMTP connection (or any other network connection, +for that matter) is an expensive process. If you have a lot of emails to send, +it makes sense to reuse an SMTP connection, rather than creating and +destroying a connection every time you want to send an email. + +There are two ways to tell an email backend to reuse a connection. Both +require an email backend instance obtained via :func:`get_connection`, which is +documented in :ref:`topic-email-backends`. + +The first approach is to obtain an email backend instance from +:func:`get_connection` and use its ``send_messages()`` method. This takes a +list of :class:`EmailMessage` (or subclass) instances, and sends them all using +that single connection. As a consequence, any :class:`connection +<EmailMessage>` set on an individual message is ignored. + +For example, if you have a function called ``get_notification_emails()`` that +returns a list of :class:`EmailMessage` objects representing some periodic +email you wish to send out, you could send these emails using a single call to +``send_messages()``:: + + from django.core import mail + + connection = mail.get_connection() # Use default email connection + messages = get_notification_emails() + connection.send_messages(messages) + +In this example, the call to ``send_messages()`` opens a connection on the +backend, sends the list of messages, and then closes the connection again. + +The second approach is to use the ``open()`` and ``close()`` methods on the +email backend to manually control the connection. ``send_messages()`` will not +open or close the connection if it is already open, so if you +manually open the connection, you can control when it is closed. For example:: + + from django.core import mail + + connection = mail.get_connection() + + # Manually open the connection. + connection.open() + + # Construct an email message that will use the connection. + email1 = mail.EmailMessage( + "Hello", + "Body goes here", + "from@example.com", + ["to1@example.com"], + connection=connection, + ) + # Send the email through its connection. The connection was already open, + # so send() leaves it open after sending. + email1.send() + + # Construct two more email messages. (Passing None as the third argument + # uses settings.DEFAULT_FROM_EMAIL as the "From:" address.) + email2 = mail.EmailMessage("Hi", "Message", None, ["to2@example.com"]) + email3 = mail.EmailMessage("Hi", "Message", None, ["to3@example.com"]) + # Send the two messages. The connection is still open. + connection.send_messages([email2, email3]) + + # Because we opened it, we need to manually close the connection. + connection.close() + +When you manually open a backend's connection, you are responsible for ensuring +it gets closed. The example above actually has a bug: if an exception occurs +while sending the messages, the connection will not be closed. You could fix +this with a try-finally statement. Or it's often more convenient to use the +backend instance as a context manager, which will automatically call ``open()`` +and ``close()`` as needed. + +This is equivalent to the previous example, but uses the backend as a +:ref:`context manager <context-managers>` to avoid leaving the connection open +on errors:: + + from django.core import mail + + with mail.get_connection() as connection: + # The backend connection is automatically opened inside the context. + email1 = mail.EmailMessage( + "Hello", + "Body goes here", + "from@example.com", + ["to1@example.com"], + connection=connection, + ) + email1.send() + + # The connection is still open, and is reused for the second send. + email2 = mail.EmailMessage("Hi", "Message", None, ["to2@example.com"]) + email3 = mail.EmailMessage("Hi", "Message", None, ["to3@example.com"]) + connection.send_messages([email2, email3]) + + # After exiting the context (either normally or because of an error), + # the backend connection is automatically closed. + .. _topic-email-backends: Email backends @@ -668,25 +768,8 @@ The email backend class has the following methods: open, it will be left open after mail has been sent. It can also be used as a context manager, which will automatically call -``open()`` and ``close()`` as needed:: - - from django.core import mail - - with mail.get_connection() as connection: - mail.EmailMessage( - subject1, - body1, - from1, - [to1], - connection=connection, - ).send() - mail.EmailMessage( - subject2, - body2, - from2, - [to2], - connection=connection, - ).send() +``open()`` and ``close()`` as needed. An example is in +:ref:`topics-sending-multiple-emails`. Django ships with several email sending backends. With the exception of the SMTP backend (which is the default), these backends are only useful during @@ -844,80 +927,6 @@ email backend. Passing ``fail_silently`` as positional argument is deprecated. -.. _topics-sending-multiple-emails: - -Sending multiple emails ------------------------ - -Establishing and closing an SMTP connection (or any other network connection, -for that matter) is an expensive process. If you have a lot of emails to send, -it makes sense to reuse an SMTP connection, rather than creating and -destroying a connection every time you want to send an email. - -There are two ways you tell an email backend to reuse a connection. - -Firstly, you can use the ``send_messages()`` method on a connection. This takes -a list of :class:`EmailMessage` (or subclass) instances, and sends them all -using that single connection. As a consequence, any :class:`connection -<EmailMessage>` set on an individual message is ignored. - -For example, if you have a function called ``get_notification_email()`` that -returns a list of :class:`EmailMessage` objects representing some periodic -email you wish to send out, you could send these emails using a single call to -``send_messages()``:: - - from django.core import mail - - connection = mail.get_connection() # Use default email connection - messages = get_notification_email() - connection.send_messages(messages) - -In this example, the call to ``send_messages()`` opens a connection on the -backend, sends the list of messages, and then closes the connection again. - -The second approach is to use the ``open()`` and ``close()`` methods on the -email backend to manually control the connection. ``send_messages()`` will not -manually open or close the connection if it is already open, so if you -manually open the connection, you can control when it is closed. For example:: - - from django.core import mail - - connection = mail.get_connection() - - # Manually open the connection - connection.open() - - # Construct an email message that uses the connection - email1 = mail.EmailMessage( - "Hello", - "Body goes here", - "from@example.com", - ["to1@example.com"], - connection=connection, - ) - email1.send() # Send the email - - # Construct two more messages - email2 = mail.EmailMessage( - "Hello", - "Body goes here", - "from@example.com", - ["to2@example.com"], - ) - email3 = mail.EmailMessage( - "Hello", - "Body goes here", - "from@example.com", - ["to3@example.com"], - ) - - # Send the two emails in a single call. - connection.send_messages([email2, email3]) - # The connection was already open so send_messages() doesn't close it. - # We need to manually close the connection. - connection.close() - - Configuring email for development ================================= |
