Class-based Emails
This package contains an approach called “class-based emails”. Similar to class-based views in django (in comparison to function-based ones), you can now implement your email as a class and use all the benefits of object-orientated programming like fiddling around with functions and all the non-DRY repetition of code you’ll usually end up with.
USPs:
Better structure and advantages of object-orientated programming over handling multiple functions!
Quick and fast creation of new emails — only worry about the things you have to think about!
No code redundancy for setting up the default mail configuration — all wrapped in the class!
The text part of the email can be automatically rendered from the HTML part — no redundant templates anymore!
Built-in (and extendable) sanity checks as a validation for forgotten variables!
Clean and easy solution for email attachments
There are two scenarios covered by this package:
Single mail: Create a single email through a class to utilise benefits of object-orientation.
Similar mails: Create a bunch of similar emails with a factory class, for example if you want to send the same content but with a personal salutation to a number of people.
Create a single email
Imagine you want to send a single email to a given user or to the system admins. Instead of having to deal with how to
end an email and worry about if the to field requires a list or string of emails… look at this example:
from django_pony_express.services.base import BaseEmailService
class MyFancyClassBasedMail(BaseEmailService):
"""
Send an email to my admins to inform them about something important.
"""
subject = _('Heads up, admins!')
template_name = 'email/my_fancy_class_based_email.html'
def get_context_data(self):
data = super().get_context_data()
data['my_variable'] = ...
return data
This is a simple example of how to create an email. We pass or set the recipients in the __init__() method and can add
more data in the get_context_data() - or just provide the context on creation as a parameter.
One big advantage is that you can create your own base class which handles all the context data you need to have for your base email template. Imagine you have an unsubscribe link or a logo in the base template. In the “old world” you have to think to pass these variables every time. Now, just wrap it up in a base class and that’s it!
And that is how you would send the email:
from django.conf import settings
email_service = MyFancyClassBasedMail(settings.MY_ADMIN_EMAIL_ADDRESS)
email_service.process()
Optionally you can set the class attribute template_txt_name to define a plain text template. If not set, the HTML
part will be used to render the plain text body.
Attachments
If you want to attach a number of files to your emails, you can do this in two ways.
The simple way is passing an absolute file path to the constructor of the service:
email_service = MyMailService(
...
attachment_list=[my_file_1, my_file_2]
)
If you want to customise the filename or even pass a mimetype, you can do as follows:
email_service = MyMailService(
...,
attachment_list=[{'filename': 'my_fancy_file.json', 'file': file_content, 'mimetype': 'application/json'}],
)
Please note that here the file content, not the file path, needs to be passed to the attachment list. If anything goes
sideways, the service will throw an EmailServiceAttachmentError exception.
Async dispatching
A general rule about external APIs is that you shouldn’t talk to them in your main thread. You don’t have any control over it, and it might be blocking your application. Therefore, it’s wise to use some kind of asynchronous method to send your emails.
The base class in this package can be used in an async way very simply. Call the process method of your email
inheriting from BaseEmailService in, for example, a thread or celery task.
Python Threads
If you don’t want to do this, you can use the ThreadEmailService class, which will wrap the sending of your emails in
a simple Python thread.
from django_pony_express.services.asynchronous.thread import ThreadEmailService
class MyThreadBasedEmail(ThreadEmailService):
pass
Other methods
In the future, we’ll add a base class for Celery and maybe django-q / django-q2.