diff options
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 ================================= |
