[Tut] Send, Receive, and Test Emails in Django - Printable Version +- Sick Gaming (https://www.sickgaming.net) +-- Forum: Programming (https://www.sickgaming.net/forum-76.html) +--- Forum: Python (https://www.sickgaming.net/forum-83.html) +--- Thread: [Tut] Send, Receive, and Test Emails in Django (/thread-99996.html) |
[Tut] Send, Receive, and Test Emails in Django - xSicKxBot - 09-28-2022 Send, Receive, and Test Emails in Django <div> <div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-top" data-payload="{"align":"left","id":"724860","slug":"default","valign":"top","ignore":"","reference":"auto","class":"","count":"1","readonly":"","score":"5","best":"5","gap":"5","greet":"Rate this post","legend":"5\/5 - (1 vote)","size":"24","width":"142.5","_legend":"{score}\/{best} - ({count} {votes})","font_factor":"1.25"}"> <div class="kksr-stars"> <div class="kksr-stars-inactive"> <div class="kksr-star" data-star="1" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="2" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="3" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="4" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" data-star="5" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> </p></div> <div class="kksr-stars-active" style="width: 142.5px;"> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> <div class="kksr-star" style="padding-right: 5px"> <div class="kksr-icon" style="width: 24px; height: 24px;"></div> </p></div> </p></div> </div> <div class="kksr-legend" style="font-size: 19.2px;"> 5/5 – (1 vote) </div> </div> <p>Some time ago, we discovered how to send an email with Python using <code><a href="https://blog.finxter.com/how-to-check-smtplib-package-version-in-python/" data-type="post" data-id="479051" target="_blank" rel="noreferrer noopener">smtplib</a></code>, a built-in email module. Back then, the focus was made on the delivery of different types of messages via SMTP server. Today, we prepared a similar tutorial but for Django.</p> <p>This popular Python web framework allows you to accelerate email delivery and make it much easier. And these code samples of sending emails with Django are going to prove that. </p> <h2><strong>A simple code example of how to send an email</strong></h2> <p>Let’s start our tutorial with a few lines of code that show you how simple it is to send an email in Django. Import send_mail in the beginning of the file:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core.mail import send_mail</pre> <p>And call the code below in the necessary place.</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">send_mail( 'That’s your subject', 'That’s your message body', '[email protected]', ['[email protected]'], fail_silently=False, ) </pre> <p>These lines are enclosed in the <code>django.core.mail</code> module that is based on <code>smtplib</code><strong>. </strong>The message delivery is carried out via SMTP host, and all the settings are set by default:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">EMAIL_HOST: 'localhost' EMAIL_PORT: 25 EMAIL_HOST_USER: (Empty string) EMAIL_HOST_PASSWORD: (Empty string) EMAIL_USE_TLS: False EMAIL_USE_SSL: False </pre> <p>Note that the character set of emails sent with <code>django.core.mail</code> are automatically set to the value of your <code>DEFAULT_CHARSET</code> setting.</p> <p>You can learn about the other default values <a href="https://docs.djangoproject.com/en/dev/ref/settings/" target="_blank" rel="noreferrer noopener">here</a>. Most likely you will need to adjust them. Therefore, let’s tweak the <em>settings.py</em> file..</p> <h3><strong>Setting up</strong></h3> <p>Before actually sending your email, you need to set up for it. So, let’s add some lines to the <em>settings.py</em> file of your Django app.</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.yourserver.com' EMAIL_PORT = '<your-server-port>' EMAIL_HOST_USER = '[email protected]' EMAIL_HOST_PASSWORD = 'your-email account-password' EMAIL_USE_TLS = True EMAIL_USE_SSL = False </pre> <p><code>EMAIL_HOST</code> is different for each email provider you use. For example, if you have a Gmail account and use their SMTP server, you’ll have <code>EMAIL_HOST = ‘smtp.gmail.com’</code>.</p> <p>Also, validate other values that are relevant to your email server. Eventually, you need to choose the way to encrypt the mail and protect your user account by setting the variable <code>EMAIL_USE_TLS</code> or <code>EMAIL_USE_SSL</code>.</p> <p>If you have an email provider that explicitly tells you which option to use, then it’s clear. Otherwise, you may try different combinations using <code>True</code> and <code>False</code> operators. Note that only one of these options can be set to <code>True</code>.</p> <p><code>EMAIL_BACKEND</code> tells <a href="https://blog.finxter.com/django-developer-income-and-opportunity/" data-type="post" data-id="248182" target="_blank" rel="noreferrer noopener">Django</a> which custom or predefined email backend will work with.</p> <p><code>EMAIL_HOST</code>. You can set up this parameter as well. </p> <h3><strong>SMTP email backend </strong></h3> <p>In the example above, <code>EMAIL_BACKEND</code> is specified as <code>django.core.mail.backends.smtp.EmailBackend</code>. It is the default configuration that uses SMTP server for email delivery. Defined email settings will be passed as matching arguments to <code>EmailBackend</code>.</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">host: EMAIL_HOST port: EMAIL_PORT username: EMAIL_HOST_USER password: EMAIL_HOST_PASSWORD use_tls: EMAIL_USE_TLS use_ssl: EMAIL_USE_SSL </pre> <p>Unspecified arguments default to <strong><code>None</code></strong>. </p> <p>As well as <code>.smtp.EmailBackend</code>, you can use:</p> <ul> <li><code>django.core.mail.backends.console.EmailBackend</code>– the console backend that composes the emails that will be sent to the standard output. Not intended for production use.</li> <li><code>django.core.mail.backends.filebased.EmailBackend</code> – the file backend that creates emails in the form of a new file per each new session opened on the backend. Not intended for production use.</li> <li><code>django.core.mail.backends.locmem.EmailBackend</code>– the in-memory backend that stores messages in the local memory cache of <code>django.core.mail.outbox</code>. Not intended for production use.</li> <li><code>django.core.mail.backends.dummy.EmailBackend</code> – the dummy cache backend that implements the cache interface and does nothing with your emails. Not intended for production use.</li> <li>Any out-of-the-box backend for Amazon SES, Mailgun, SendGrid, and other services. </li> </ul> <h2><strong>How to send emails via SMTP </strong></h2> <p>Once you have that configured, all you need to do to send an email is to import the <code>send_mail</code> or <code>send_mass_mailfunction</code> from <code>django.core.mail</code>. These functions differ in the connection they use for messages. <code>send_mailuses</code> a separate connection for each message. <code>send_mass_mailopens</code> a single connection to the mail server and is mostly intended to handle mass emailing. </p> <h3><strong>Sending email with send_mail</strong></h3> <p>This is the most basic function for email delivery in Django. It comprises four obligatory parameters to be specified: <code>subject</code>, <code>message</code>, <code>from_email</code>, and <code>recipient_list</code>. </p> <p>In addition to them, you can adjust the following:</p> <ul> <li><code>auth_user</code>: If <code>EMAIL_HOST_USER</code> has not been specified, or you want to override it, this username will be used to authenticate to the SMTP server. </li> <li><code>auth_password</code>: If <code>EMAIL_HOST_PASSWORD</code> has not been specified, this password will be used to authenticate to the SMTP server.</li> <li><code>connection</code>: The optional email backend you can use without tweaking <code>EMAIL_BACKEND</code>.</li> <li><code>html_message</code>: Lets you send multipart emails.</li> <li><code>fail_silently</code>: A boolean that controls how the backend should handle errors. If <code>True</code> – exceptions will be silently ignored. If <code>False</code> – <code>smtplib.SMTPException</code> will be raised. </li> </ul> <p>For example, it may look like this:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core.mail import send_mail send_mail( subject = 'That’s your subject' message = 'That’s your message body' from_email = '[email protected]' recipient_list = ['[email protected]',] auth_user = 'Login' auth_password = 'Password' fail_silently = False, ) </pre> <p>Other functions for email delivery include <code>mail_admins</code> and <code>mail_managers</code>. Both are shortcuts to send emails to the recipients predefined in ADMINS and MANAGERS settings respectively.</p> <p>For them, you can specify such arguments as <code>subject</code>, <code>message</code>, <code>fail_silently</code>, <code>connection</code>, and <code>html_message</code>.</p> <p>The <code>from_email</code> argument is defined by the <code>SERVER_EMAIL</code> setting.</p> <h3><strong>What is </strong><strong>EmailMessage</strong><strong> for? </strong></h3> <p>If the email backend handles the email sending, the <code>EmailMessage</code> class answers for the message creation. You’ll need it when some advanced features like BCC or an attachment are desirable. That’s how an initialized <code>EmailMessage</code> may look:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core.mail import EmailMessage email = EmailMessage( subject = 'That’s your subject', body = 'That’s your message body', from_email = '[email protected]', to = ['[email protected]'], bcc = ['[email protected]'], reply_to = ['[email protected]'], ) </pre> <p>In addition to the <code>EmailMessage</code> objects you can see in the example, there are also other optional parameters:</p> <ul> <li><code>connection</code>: defines an email backend instance for multiple messages. </li> <li><code>attachments</code>: specifies the attachment for the message.</li> <li><code>headers</code>: specifies extra headers like Message-ID or CC for the message. </li> <li><code>cc</code>: specifies email addresses used in the “CC” header.</li> </ul> <p>The methods you can use with the <code>EmailMessage</code> class are the following:</p> <ul> <li><code>send</code>: get the message sent.</li> <li><code>message</code>: composes a MIME object (<code>django.core.mail.SafeMIMEText</code> or <code>django.core.mail.SafeMIMEMultipart</code>).</li> <li><code>recipients</code>: returns a list of the recipients specified in all the attributes including to, cc, and bcc. </li> <li><code>attach</code>: creates and adds a file attachment. It can be called with a MIMEBase instance or a triple of arguments consisting of filename, content, and mime type.</li> <li><code>attach_file</code>: creates an attachment using a file from a filesystem. We’ll talk about adding attachments a bit later.</li> </ul> <h3><strong>How to send multiple emails</strong></h3> <p>To deliver a message via SMTP, you need to open a connection and close it afterwards. This approach is quite awkward when you need to send multiple transactional emails. Instead, it is better to create one connection and reuse it for all messages.</p> <p>This can be done with the <code>send_messages</code> method that the email backend API has. Check out the following example:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core import mail connection = mail.get_connection() connection.open() email1 = mail.EmailMessage( 'That’s your subject', 'That’s your message body', '[email protected]', ['[email protected]'], connection=connection, ) email1.send() email2 = mail.EmailMessage( 'That’s your subject #2', 'That’s your message body #2', '[email protected]', ['[email protected]'], ) email3 = mail.EmailMessage( 'That’s your subject #3', 'That’s your message body #3', '[email protected]', ['[email protected]'], ) connection.send_messages([email2, email3]) connection.close() </pre> <p>What you can see here is that the connection was opened for <code>email1</code>, and <code>send_messages</code> uses it to send emails #2 and #3. After that, you close the connection manually. </p> <h3><strong>How to send multiple emails with send_mass_mail</strong></h3> <p><code>send_mass_mail</code> is another option to use only one connection for sending different messages. </p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">message1 = ('That’s your subject #1', 'That’s your message body #1', '[email protected]', ['[email protected]', '[email protected]']) message2 = ('That’s your subject #2', 'That’s your message body #2', '[email protected]', ['[email protected]']) message3 = ('That’s your subject #3', 'That’s your message body #3', '[email protected]', ['[email protected]']) send_mass_mail((message1, message2, message3), fail_silently=False) </pre> <p>Each email message contains a datatuple made of <code>subject</code>, <code>message</code>, <code>from_email</code>, and <code>recipient_list</code>. Optionally, you can add other arguments that are the same as for <code>send_mail</code>.</p> <h3><strong>How to send an HTML email</strong></h3> <p>All versions starting from 1.7 let you send an email with HTML content using <code>send_mail</code> like this:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core.mail import send_mail subject = 'That’s your subject' html_message = render_to_string('mail_template.html', {'context': 'values'}) plain_message = strip_tags(html_message) from_email = '[email protected]>' to = '[email protected]' mail.send_mail(subject, plain_message, from_email, [to], html_message=html_message) </pre> <p>Older versions users will have to mess about with <code>EmailMessage</code> and its subclass <code>EmailMultiAlternatives</code>. It lets you include different versions of the message body using the <code>attach_alternative</code> method. For example:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core.mail import EmailMultiAlternatives subject = 'That’s your subject' from_email = '[email protected]>' to = '[email protected]' text_content = 'That’s your plain text.' html_content = '<p>That’s <strong>the HTML part</strong></p>' message = EmailMultiAlternatives(subject, text_content, from_email, [to]) message.attach_alternative(html_content, "text/html") message.send() </pre> <h3><strong>How to send an email with attachments</strong></h3> <p>In the <code>EmailMessage</code> section, we’ve already mentioned sending emails with attachments. This can be implemented using <code>attach</code> or <code>attach_file</code> methods.</p> <p>The first one creates and adds a file attachment through three arguments – filename, content, and mime type.</p> <p>The second method uses a file from a filesystem as an attachment. That’s how each method would look like in practice:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">message.attach('Attachment.pdf', file_to_be_sent, 'file/pdf')</pre> <p>or</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">message.attach_file('/documents/Attachment.pdf')</pre> <h2><strong>Custom email backend</strong></h2> <p>You’re not limited to the abovementioned email backend options and can tailor your own. For this, you can use standard backends as a reference. Let’s say, you need to create a custom email backend with the <code>SMTP_SSL</code> connection support required to interact with Amazon SES.</p> <p>The default SMTP backend will be the reference. First, add a new email option to <em>settings.py</em>. </p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">AWS_ACCESS_KEY_ID = 'your-aws-access-key-id' AWS_SECRET_ACCESS_KEY = 'your-aws-secret-access-key' AWS_REGION = 'your-aws-region' EMAIL_BACKEND = 'your_project_name.email_backend.SesEmailBackend' </pre> <p>Make sure that you are allowed to send emails with Amazon SES using these <code>AWS_ACCESS_KEY_ID</code> and <code>AWS_SECRET_ACCESS_KEY</code> (or error message will tell you about it :D)</p> <p>Then create a file <em>your_project_name/email_backend.py</em> with the following content: </p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import boto3 from django.core.mail.backends.smtp import EmailBackend from django.conf import settings class SesEmailBackend(EmailBackend): def __init__( self, fail_silently=False, **kwargs ): super().__init__(fail_silently=fail_silently) self.connection = boto3.client( 'ses', aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, region_name=settings.AWS_REGION, ) def send_messages(self, email_messages): for email_message in email_messages: self.connection.send_raw_email( Source=email_message.from_email, Destinations=email_message.recipients(), RawMessage={"Data": email_message.message().as_bytes(linesep="\r\n")} ) </pre> <p>This is the minimum needed to send an email using SES. Surely you will need to add some error handling, input sanitization, retries etc. but this is out of our topic. </p> <p>You might see that we have imported <a href="https://blog.finxter.com/how-to-install-boto3-in-python/" data-type="post" data-id="35819" target="_blank" rel="noreferrer noopener">boto3</a> in the beginning of the file. Don’t forget to install it using a command</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pip install boto3</pre> <p>It’s not necessary to reinvent the wheel every time you need a custom email backend. You can find already existing libraries, or just receive SMTP credentials in your Amazon console and use the default email backend. It’s just about figuring out the best option for you and your project.</p> <h2><strong>Sending emails using SES from Amazon</strong></h2> <p>So far, you can benefit from several services that allow you to send transactional emails at ease. If you can’t choose one, check out our blog post about Sendgrid vs. Mandrill vs. Mailgun. It will help a lot. At this point, Mailtrap has launched its own sending solution.</p> <p>So, you could easily start sending transactional emails in Django using our guide. But today, we’ll discover how to make your Django app send emails via Amazon SES. It is one of the most popular services so far. Besides, you can take advantage of a ready-to-use Django email backend for this service – <a href="https://github.com/django-ses/django-ses" target="_blank" rel="noreferrer noopener">django-ses</a>.</p> <h3><strong>Set up the library</strong></h3> <p>You need to execute pip install django-ses to install django-ses. Once it’s done, tweak your <em>settings.py</em> with the following line:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">EMAIL_BACKEND = 'django_ses.SESBackend'</pre> <h3><strong>AWS credentials</strong></h3> <p>Don’t forget to set up your AWS account to get the required credentials – AWS access keys that consist of access key ID and secret access key.</p> <p>For this, add a user in Identity and Access Management (IAM) service.</p> <p>Then, choose a user name and Programmatic access type. Attach <code>AmazonSESFullAccess</code> permission and create a user. Once you’ve done this, you should see AWS access keys. Update your <em>settings.py</em><strong>:</strong></p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">AWS_ACCESS_KEY_ID = '********' AWS_SECRET_ACCESS_KEY = '********' </pre> <h3><strong>Email sending</strong></h3> <p>Now, you can send your emails using <code>django.core.mail.send_mail</code>:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core.mail import send_mail send_mail( 'That’s your subject', 'That’s your message body', '[email protected]', ['[email protected]'] ) </pre> <p><code>django-ses</code> is not the only preset email backend you can leverage. At the end of this article, you’ll find more useful libraries to optimize email delivery of your Django app. But first, a step you should never send emails without.</p> <h2><strong>Testing email sending in Django </strong></h2> <p>Once you’ve got everything prepared for sending email messages, it is necessary to do some initial testing of your mail server. In Python, this can be done with one command:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">python -m smtpd -n -c DebuggingServer localhost:1025</pre> <p>This allows you to send emails to your local SMTP server. The DebuggingServer feature won’t actually send the email but will let you see the content of your message in the shell window. That’s an option you can use off-hand.</p> <h3><strong>Django’s TestCase</strong></h3> <p>TestCase is a solution to test a few aspects of your email delivery. It uses locmem.EmailBackend, which, as you remember, stores messages in the local memory cache – django.core.mail.outbox. So, this test runner does not actually send emails. Once you’ve selected this email backend</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'</pre> <p>you can use the following unit test sample to test your email sending capability.</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core import mail from django.test import TestCase class EmailTest(TestCase): def test_send_email(self): mail.send_mail( 'That’s your subject', 'That’s your message body', '[email protected]', ['[email protected]'], fail_silently=False, ) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, 'That’s your subject') self.assertEqual(mail.outbox[0].body, 'That’s your message body') </pre> <p>This code will test not only your email sending but also the correctness of the email subject and message body. </p> <h3><strong>Testing with Mailtrap</strong></h3> <p>Mailtrap can be a rich solution for testing. First, it lets you test not only the SMTP server but also the email content and do other essential checks from the email testing checklist. Second, it is a rather easy-to-use tool. </p> <p>All you need to do is to copy the SMTP credentials from your demo inbox and tweak your <em>settings.py</em>. Or you can just copy/paste these four lines from the Integrations section by choosing Django in the pop-up menu. </p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">EMAIL_HOST = 'smtp.mailtrap.io' EMAIL_HOST_USER = '********' EMAIL_HOST_PASSWORD = '*******' EMAIL_PORT = '2525' </pre> <p>After that, feel free to send your <a href="https://blog.finxter.com/html-developer-income-and-opportunity/" data-type="post" data-id="191232" target="_blank" rel="noreferrer noopener">HTML</a>/<a href="https://blog.finxter.com/css-developer-income-and-opportunity/" data-type="post" data-id="193134" target="_blank" rel="noreferrer noopener">CSS</a> email with an attachment to check how it goes.</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django.core.mail import send_mail subject = 'That’s your subject' html_message = render_to_string('mail_template.html', {'context': 'values'}) plain_message = strip_tags(html_message) from_email = '[email protected]>' to = '[email protected]' mail.send_mail(subject, plain_message, from_email, [to], html_message=html_message) message.attach('Attachment.pdf', file_to_be_sent, 'file/pdf') </pre> <p>If there is no message in the Mailtrap Demo inbox or there are some issues with HTML content, you need to polish your code. </p> <h2><strong>Django email libraries to simplify your life</strong></h2> <p>As a conclusion to this blog post about sending emails with Django, we’ve included a brief introduction of a few libraries that will facilitate your email workflow. </p> <h3><strong>django-anymail</strong></h3> <p>This is a collection of email backends and webhooks for numerous famous email services including SendGrid, Mailgun, and others. <code>django-anymail</code> works with the <code>django.core.mail</code> module and normalizes the functionality of transactional email service providers. </p> <h3><strong>django-mailer</strong></h3> <p><a href="https://github.com/pinax/django-mailer" target="_blank" rel="noreferrer noopener">django-mailer</a> is a Django app you can use to queue email sending. With it, scheduling your emails is much easier. </p> <h3><strong>django-post_office</strong></h3> <p>With this app, you can send and manage your emails. <a href="https://github.com/ui/django-post_office">django-post_office</a> offers many cool features like asynchronous email sending, built-in scheduling, multiprocessing, etc. </p> <h3><strong>django-templated-email</strong></h3> <p>This app is about sending templated emails. In addition to its own functionalities, <a href="https://github.com/vintasoftware/django-templated-email">django-templated-email</a> can be used in tow with <code>django-anymail</code> to integrate transactional email service providers.</p> <h2><strong>How to receive emails in Django</strong></h2> <p>To receive emails in Django, it is better to use the <a href="https://github.com/coddingtonbear/django-mailbox">django-mailbox</a> development library if you need to import messages from local mailboxes, POP3, IMAP, or directly receive messages from Postfix or Exim4. </p> <p>While using Django-mailbox, mailbox functions as a message queue that is being gradually processed. The library helps retrieve email messages and then erases them so they are not downloaded again the next time.</p> <p><strong>Mailbox types supported by django-mailbox:</strong> POP3, IMAP, Gmail IMAP with Oauth2 authentication, local file-based mailboxes like Maildir, Mbox, Babyl, MH, or MMDF.</p> <p>Here’s a step-by-step guide on how to quickly set up your Django-mailbox and start receiving emails.</p> <h3><strong>Installation</strong></h3> <p>There are two ways to install django-mailbox: </p> <p>1. From pip:</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pip install django-mailbox</pre> <p>2. From the <a href="https://github.com/coddingtonbear/django-mailbox/">github-repository:</a></p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">git clone https://github.com/coddingtonbear/django-mailbox.git cd django-mailbox python setup.py install </pre> <ul> <li>After installing the package, go to <em>settings.py</em> file of the django project and add <code>django_mailbox</code><strong> </strong>to <code>INSTALLED_APPS</code>.</li> <li>Then, run python <code>manage.py migrate django_mailbox</code> from your project file to create the necessary database tables.</li> <li>Finally, go to your project’s Django Admin and create a mailbox to consume.</li> <li>Don’t forget to verify if your mailbox was set up right. You can do that from a shell opened to your project’s directory, using the <code>getmail</code> command running <code>python manage.py getmail</code></li> </ul> <p>When you are done with the installation and checking the configurations, it’s time to receive incoming emails. There are five different ways to do that.</p> <ol> <li><strong>In your code</strong></li> </ol> <p>Use the <code>get_new_mail</code> method to collect new messages from the server.</p> <ol start="2"> <li><strong>With Django Admin</strong></li> </ol> <p>Go to Django Admin, then to ‘Mailboxes’ page, check all the mailboxes you need to receive emails from. At the top of the list with mailboxes, choose the action selector ‘Get new mail’ and click ‘Go’.</p> <ol start="3"> <li><strong>With cron job</strong></li> </ol> <p>Run the management command <code>getmail</code> in <code>python manage.py getmail</code></p> <ol start="4"> <li><strong>Directly from Exim4</strong></li> </ol> <p>To configure Exim4 to receive incoming mail begin with adding a new router:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">django_mailbox: debug_print = 'R: django_mailbox for $localpart@$domain' driver = accept transport = send_to_django_mailbox domains = mydomain.com local_parts = emailusernameone : emailusernametwo </pre> <p>In case the email addresses you are trying to add are handled by other routers, disable them. For this change, the contents of <code>local_parts</code> must match a colon-delimited list of usernames for which you would like to receive mail.</p> <p>5. <strong>Directly from Postfix</strong></p> <p>With Postfix get new mail to a script using <code>pipe</code>. The steps to set up receiving incoming mail directly from Postfix are pretty much the same as with Exim4. However, you might need to check out the <a href="http://www.postfix.org/pipe.8.html" target="_blank" rel="noreferrer noopener">Postfix pipe documentation</a>. </p> <p>There’s also an option to subscribe to the incoming <code>django-mailbox</code> signal if you need to process your incoming mail at the time that suits you best.</p> <p>Use this piece of code to do that:</p> <pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from django_mailbox.signals import message_received from django.dispatch import receiver @receiver(message_received) def dance_jig(sender, message, **args): print "I just received a message titled %s from a mailbox named %s" % (message.subject, message.mailbox.name, ) </pre> <p>Keep in mind that this should be loaded to <em><strong>models.py</strong></em> or elsewhere early enough for the signal not to be fired before your signal handler’s registration is processed.</p> <hr class="wp-block-separator has-alpha-channel-opacity"/> <p>We hope that you find our guide helpful and the list of packages covered help facilitate your email workflow. You can always find more apps at <a href="https://djangopackages.org/grids/g/email/">Django Packages</a>. </p> <p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> This article was originally published on Mailtrap’s blog: <a rel="noreferrer noopener" href="https://mailtrap.io/blog/django-send-email/" target="_blank">Sending emails in Django with code examples</a>. We have repurposed it on the Finxter blog with their permission! <img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f44c.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p> </div> https://www.sickgaming.net/blog/2022/09/27/send-receive-and-test-emails-in-django/ |