Hacking MailFactory¶
MailFactory is a tool to help you manage your emails in the real world.
That means that for the same email, regarding the context, you may want a different branding, different language, etc.
Specify the language for your emails¶
If you need to specify the language for your email, other than the currently
used language, you can do so by overriding the get_language
method on your
custom class.
Let’s say that our user has a language_code
as a profile attribute:
class ActivationEmail(BaseMail):
template_name = 'activation'
params = ['user', 'activation_key']
def get_language(self):
return self.context['user'].get_profile().language_code
Force a param for all emails¶
You can also overriding the get_params
method of a custom ancestor class to
add some mandatory parameters for all your emails:
class MyProjectBaseMail(BaseMail):
def get_params(self):
params = super(MyProjectBaseMail, self).get_params()
return params.append('user')
class ActivationEmail(MyProjectBaseMail):
template_name = 'activation'
params = ['activation_key']
This way, all your emails will have the user in the context by default.
Add context data¶
If you have some information that must be added to every email context, you can put them here:
class MyProjectBaseMail(BaseMail):
def get_context_data(self, **kwargs):
data = super(MyProjectBaseMail, self).get_context_data(**kwargs)
data['site_name'] = settings.SITE_NAME
data['site_url'] = settings.SITE_URL
return data
Add attachments¶
Same thing here, if your branding needs a logo or a header in every emails, you can define it here:
from django.contrib.staticfiles import finders
class MyProjectBaseMail(BaseMail):
def get_attachments(self, files=None):
attach = super(MyProjectBaseMail, self).get_attachments(files)
attach.append((finders.find('mails/header.png'),
'header.png', 'image/png'))
return attach
Now, if you want to use this attached image in your html template, you need to
use the cid URI scheme with the name of the attachment, which is the second
item of the tuple (header.png
in our example above):
<img src="cid:header.png" alt="This is the header" />
Template loading¶
By default, the template parts will be searched in:
templates/mails/TEMPLATE_NAME/LANGUAGE_CODE/
templates/mails/TEMPLATE_NAME/
But you may want to search in different locations, ie:
templates/SITE_DOMAIN/mails/TEMPLATE_NAME/
To do that, you can override the get_template_part
method:
class ActivationEmail(BaseMail):
template_name = 'activation'
params = ['activation_key', 'site']
def get_template_part(self, part):
"""Return a mail part (body, html body or subject) template
Try in order:
1/ domain specific localized:
example.com/mails/activation/fr/
2/ domain specific:
example.com/mails/activation/
3/ default localized:
mails/activation/fr/
4/ fallback:
mails/activation/
"""
templates = []
site = self.context['site']
# 1/ {{ domain_name }}/mails/{{ template_name }}/{{ language_code}}/
templates.append(path.join(site.domain,
'mails',
self.template_name,
self.lang,
part))
# 2/ {{ domain_name }}/mails/{{ template_name }}/
templates.append(path.join(site.domain,
'mails',
self.template_name,
part))
# 3/ and 4/ provided by the base class
base_temps = super(MyProjectBaseMail, self).get_template_part(part)
return templates + base_temps
get_template_part
returns a list of template and will take the first one
available.