Imagine that we need to deliver some specific dashboards or report frequently, it’s more convenient to send them automatically rather than manually. In this blog I’ll talk about how to send an e-mail with Python in the following points:
- Setting up a fake SMTP server with Python
- Sending e-mails with Python
- Test sending e-mails with unittest.mock
Setting up a fake SMTP server with Python
-m mod
: run library module as a script (terminates option list)-c cmd
: program passed in as string (terminates option list)
This command helps us to create a new debugging server, the messages will be discarded, and printed on stdout.
We use sudo
in this case because we’re using port 25, if you don’t want that
you can use a port higher than 1024.
Sending e-mails with Python
For building mail, I created the build_email()
function with mailer
module
to specify the sender, the destination, the subject, mail’s content, and
attachment if you want. For sending mail by SMTP, I created the send_email()
function with smtplib
module. I firstly created an SMTP
instance that
encapsulates an SMTP
connection with smtplib.SMTP
, assigning host
, port
and local_hostname
; then sending mail with this instance; exit when it
finished.
If you want to send an E-mail from “from@domain.com” to “to@domain.com”, with
“subject” as the subject, “message” as the content and “test_df.csv” as the
attachment, using the SMTP
instance “localhost:25”, you can do like:
Then you will get the following result in you terminal:
Test sending e-mails with unittest.mock
Mocking the SMTP
instance means we replace the original SMTP
instance with
a mock, then we will test the functions above with it.
At the beginning of the test, I applied unittest.mock.patch()
as a context
manager to mock the smtplib.SMTP
class; then the elements for sending E-mail
are specified. Since I’ve mocked the SMTP
, there is no more need to detail
the host and port. Before testing, I retrieved the instance of mocked SMTP
object, which will be used in the following tests.
Now, let’s test! I first tested if the mocked SMTP instance is called and only called once.
Then check the E-mail’s elements are correspond with the assignment. If you want
to test the functions with attachment, you can check like
self.assertEqual(msg.attachments[0][0], 'test_df.csv')
.
Moreover, we can also check if sendmail()
has been called only once with the
given arguments by assert_called_once_with()
.
We can check the mock’ calls are equal to a specific list of calls in a specific order as well.
Reference
- Daniele Esposti, “Mocking objects in unit tests”, expobrain.net. [Online]. Available: https://expobrain.net/2013/08/27/mocking-objects-in-unit-tests/
- Stuart Colville, “Fake SMTP server with Python”, muffinresearch.co.uk. [Online]. Available: https://muffinresearch.co.uk/fake-smtp-server-with-python/
- “How to setup a fake SMTP server to catch all mails?”, serverfault.com. [Online]. Available: https://serverfault.com/questions/207619/how-to-setup-a-fake-smtp-server-to-catch-all-mails
- “smtpd — SMTP Server”, docs.python.org. [Online]. Available: https://docs.python.org/3/library/smtpd.html#debuggingserver-objects
- “send email via hotmail in python”, stackoverflow.com. [Online]. Available: https://stackoverflow.com/questions/13411486/send-email-via-hotmail-in-python
- “unittest.mock — mock object library”, docs.python.org. [Online]. Available: https://docs.python.org/3/library/unittest.mock.html
- “10.1.2 What information is listed”, www.gnu.org. [Online]. Available: http://www.gnu.org/software/coreutils/manual/html_node/What-information-is-listed.html#What-information-is-listed
- ribkhan, “Email newsletter marketing online”, pixabay.com. [Online]. Available: https://pixabay.com/illustrations/email-newsletter-marketing-online-3249062/