send_mass_emails with EmailMultiAlternatives

That is send_mass_mail() rewritten to use EmailMultiAlternatives:

from django.core.mail import get_connection, EmailMultiAlternatives

def send_mass_html_mail(datatuple, fail_silently=False, user=None, password=None, 
                        connection=None):
    """
    Given a datatuple of (subject, text_content, html_content, from_email,
    recipient_list), sends each message to each recipient list. Returns the
    number of emails sent.

    If from_email is None, the DEFAULT_FROM_EMAIL setting is used.
    If auth_user and auth_password are set, they're used to log in.
    If auth_user is None, the EMAIL_HOST_USER setting is used.
    If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.

    """
    connection = connection or get_connection(
        username=user, password=password, fail_silently=fail_silently)
    messages = []
    for subject, text, html, from_email, recipient in datatuple:
        message = EmailMultiAlternatives(subject, text, from_email, recipient)
        message.attach_alternative(html, 'text/html')
        messages.append(message)
    return connection.send_messages(messages)

I followed a mixed approach, sending to users both plain text and html messages and personalizing messages for every user.

I started from the section Sending multiple emails od Django documentation.

from django.conf import settings
from django.contrib.auth.models import User
from django.core import mail
from django.core.mail.message import EmailMultiAlternatives
from django.template.loader import get_template
from django.template import Context

...

connection = mail.get_connection()
connection.open()
messages = list()

for u in users:
    c = Context({ 'first_name': u.first_name, 'reseller': self,})
    subject, from_email, to = 'new reseller', settings.SERVER_EMAIL, u.email
    text_content = plaintext.render(c)
    html_content = htmly.render(c)
    msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
    msg.attach_alternative(html_content, "text/html")
    messages.append(msg)

connection.send_messages(messages)
connection.close()

It's not possible to directly use send_mass_mail() with EmailMultiAlternatives. However, according to the Django documentation, send_mass_mail() is simply a wrapper that makes use of the EmailMessage class. EmailMultiAlternatives is a subclass of EmailMessage. EmailMessage has a 'connection' parameter allowing you to specify a single connection to use when sending the message to all recipients - i.e. the same functionality as provided by send_mass_mail(). You can use the get_connection() function to obtain an SMTP connection as defined by the SMTP settings in settings.py.

I believe that the following (untested) code should work:

from django.core.mail import get_connection, EmailMultiAlternatives

connection = get_connection() # uses SMTP server specified in settings.py
connection.open() # If you don't open the connection manually, Django will automatically open, then tear down the connection in msg.send()

html_content = render_to_string('newsletter.html', {'newsletter': n,})               
text_content = "..."                      
msg = EmailMultiAlternatives("subject", text_content, "from@bla", ["to@bla", "to2@bla", "to3@bla"], connection=connection)                                      
msg.attach_alternative(html_content, "text/html")                                                                                                                                                                               
msg.send() 

connection.close() # Cleanup

Tags:

Django