Création de modèles d'e-mails avec Django


207

Je veux envoyer des e-mails HTML, en utilisant des modèles Django comme celui-ci:

<html>
<body>
hello <strong>{{username}}</strong>
your account activated.
<img src="mysite.com/logo.gif" />
</body>

Je ne trouve rien send_mail, et django-mailer envoie uniquement des modèles HTML, sans données dynamiques.

Comment utiliser le moteur de modèle de Django pour générer des e-mails?


3
Avis de Django 1.7offres html_messageà send_email stackoverflow.com/a/28476681/953553
andilabs

Salut @anakin, je lutte depuis longtemps avec ce problème et j'ai décidé de créer un package pour cela. Je serais très heureux d'avoir vos commentaires: github.com/charlesthk/django-simple-mail
Charlesthk

Réponses:


385

À partir des documents , pour envoyer des e-mails HTML, vous souhaitez utiliser d'autres types de contenu, comme ceci:

from django.core.mail import EmailMultiAlternatives

subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = 'This is an important message.'
html_content = '<p>This is an <strong>important</strong> message.</p>'
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()

Vous aurez probablement besoin de deux modèles pour votre e-mail - un texte brut qui ressemble à ceci, stocké dans votre répertoire de modèles sous email.txt:

Hello {{ username }} - your account is activated.

et un HTMLy, stocké sous email.html:

Hello <strong>{{ username }}</strong> - your account is activated.

Vous pouvez ensuite envoyer un e-mail à l'aide de ces deux modèles en utilisant get_template, comme ceci:

from django.core.mail import EmailMultiAlternatives
from django.template.loader import get_template
from django.template import Context

plaintext = get_template('email.txt')
htmly     = get_template('email.html')

d = Context({ 'username': username })

subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = plaintext.render(d)
html_content = htmly.render(d)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()

40
Je pense que vous pouvez simplifier cela avec render_to_string , ce qui vous permettrait de perdre les lignes distinctes affectant les modèles à plaintextet htmly, et de simplement définir des modèles et des contextes lorsque vous définissez text_contentet html_content.
cms_mgr

@cms_mgr Pouvez-vous élaborer ce que vous voulez dire et comment nous pouvons l'utiliser
akki

3
@akki voir la réponse d'Andi ci-dessous, ce qui simplifie également la partie alternative grâce à l'ajout du paramètre html_message à send_email () dans Django 1.7
Mike S

Pardonnez-moi, mais pourquoi utilisons-nous txt et htmly les deux en même temps pour un courrier. Je n'ai pas compris cette logique
Shashank Vivek

ce ne sont que des exemples pour montrer différents types de méthodes, vous pouvez utiliser n'importe laquelle d'entre elles @ShashankVivek
erdemlal

242

Garçons et filles!

Depuis la méthode 1.7 de Django dans send_email , le html_messageparamètre a été ajouté.

html_message: si html_message est fourni, l'e-mail résultant sera un e-mail en plusieurs parties / alternatif avec un message comme type de contenu text / plain et html_message comme type de contenu text / html.

Vous pouvez donc simplement:

from django.core.mail import send_mail
from django.template.loader import render_to_string


msg_plain = render_to_string('templates/email.txt', {'some_params': some_params})
msg_html = render_to_string('templates/email.html', {'some_params': some_params})

send_mail(
    'email title',
    msg_plain,
    'some@sender.com',
    ['some@receiver.com'],
    html_message=msg_html,
)

1
Remarquez si 'email.txt' et 'email.html' sont dans un modèle de répertoire tel que défini dans les paramètres que juste render_to_string ('email.txt', {'some_params': some_params} _
Bruno Vermeulen

Merci pour l' render_to_stringastuce, très pratique.
hoefling le

1
Bonne solution! Cependant, avec send_mailn'est pas possible de définir un en-tête personnalisé comme ie Return-Pathqui peut être défini avec leEmailMultiAlternatives's constructor header parameter
Qlimax

26

J'ai créé django-templated-email dans le but de résoudre ce problème, inspiré par cette solution (et la nécessité, à un moment donné, de passer de l'utilisation de modèles django à l'utilisation d'un ensemble mailchimp, etc. de modèles pour les e-mails transactionnels et modèles pour mon propre projet). C'est toujours un travail en cours, mais pour l'exemple ci-dessus, vous feriez:

from templated_email import send_templated_mail
send_templated_mail(
        'email',
        'from@example.com',
        ['to@example.com'],
        { 'username':username }
    )

Avec l'ajout de ce qui suit à settings.py (pour compléter l'exemple):

TEMPLATED_EMAIL_DJANGO_SUBJECTS = {'email':'hello',}

Cela recherchera automatiquement les modèles nommés 'templated_email / email.txt' et 'templated_email / email.html' pour les parties plain et html respectivement, dans les répertoires / chargeurs de modèle django normaux (se plaindre s'il ne peut pas en trouver au moins un) .


1
Cela me semble correct. J'ai réduit cela et l'ai jeté dans un ticket pour ajouter django.shortcuts.send_templated_mail: code.djangoproject.com/ticket/17193
Tom Christie

Cool, heureux de le voir proposé comme outil pour le noyau django. Mon cas d'utilisation / focus pour la lib est un peu plus grand que le simple raccourci, (basculement facile entre les fournisseurs de messagerie qui ont des API de clé / valeur pour l'envoi de courrier), mais cela semble être une fonctionnalité manquante du noyau
Darb

15

Utilisez EmailMultiAlternatives et render_to_string pour utiliser deux modèles alternatifs (un en texte brut et un en html):

from django.core.mail import EmailMultiAlternatives
from django.template import Context
from django.template.loader import render_to_string

c = Context({'username': username})    
text_content = render_to_string('mail/email.txt', c)
html_content = render_to_string('mail/email.html', c)

email = EmailMultiAlternatives('Subject', text_content)
email.attach_alternative(html_content, "text/html")
email.to = ['to@example.com']
email.send()

5

J'ai créé Django Simple Mail pour avoir un modèle simple, personnalisable et réutilisable pour chaque e-mail transactionnel que vous souhaitez envoyer.

Le contenu et les modèles des e-mails peuvent être modifiés directement depuis l'administrateur de django.

Avec votre exemple, vous enregistreriez votre email:

from simple_mail.mailer import BaseSimpleMail, simple_mailer


class WelcomeMail(BaseSimpleMail):
    email_key = 'welcome'

    def set_context(self, user_id, welcome_link):
        user = User.objects.get(id=user_id)
        return {
            'user': user,
            'welcome_link': welcome_link
        }


simple_mailer.register(WelcomeMail)

Et envoyez-le de cette façon:

welcome_mail = WelcomeMail()
welcome_mail.set_context(user_id, welcome_link)
welcome_mail.send(to, from_email=None, bcc=[], connection=None, attachments=[],
                   headers={}, cc=[], reply_to=[], fail_silently=False)

J'adorerais avoir des commentaires.


Cela aiderait beaucoup si vous téléchargez une application de démonstration de votre package sur votre dépôt.
ans2human

Salut @ ans2human merci pour cette suggestion, je l'ajoute à la liste des améliorations!
Charlesthk

3

Il y a une erreur dans l'exemple .... si vous l'utilisez tel qu'il est écrit, l'erreur suivante se produit:

<type 'exceptions.Exception'>: l'objet 'dict' n'a pas d'attribut 'render_context'

Vous devrez ajouter l'importation suivante:

from django.template import Context

et changez le dictionnaire pour qu'il soit:

d = Context({ 'username': username })

Voir http://docs.djangoproject.com/en/1.2/ref/templates/api/#rendering-a-context


Merci - c'est réglé maintenant.
Dominic Rodger

3

Django Mail Templated est une application Django riche en fonctionnalités pour envoyer des e-mails avec le système de modèles Django.

Installation:

pip install django-mail-templated

Configuration:

INSTALLED_APPS = (
    ...
    'mail_templated'
)

Modèle:

{% block subject %}
Hello {{ user.name }}
{% endblock %}

{% block body %}
{{ user.name }}, this is the plain text part.
{% endblock %}

Python:

from mail_templated import send_mail
send_mail('email/hello.tpl', {'user': user}, from_email, [user.email])

Plus d'informations: https://github.com/artemrizhov/django-mail-templated


C'était vraiment facile à utiliser. Merci.
cheenbabes du

Bonjour, comment puis-je définir tous mes destinataires sur BCC?
aldesabido

@aldesabido Ceci est juste un wrapper autour de la classe EmailMessage standard de Django. Vous devriez donc lire la documentation officielle lorsque vous recherchez de telles fonctionnalités: docs.djangoproject.com/en/1.10/topics/email Jetez également un coup d'œil à une question similaire: stackoverflow.com/questions/3470172/…
raacer

Pour être plus précis, l'EmailMessage standard n'est pas encapsulé, mais hérité. C'est-à-dire que c'est l'extension pour la classe standard :)
raacer

Possible d'inclure JS / CSS dans le modèle?
Daniel Shatz

3

Je sais que c'est une vieille question, mais je sais aussi que certaines personnes sont comme moi et recherchent toujours des réponses actualisées, car les anciennes réponses peuvent parfois avoir des informations obsolètes si elles ne sont pas mises à jour.

C'est maintenant janvier 2020, et j'utilise Django 2.2.6 et Python 3.7

Remarque: J'utilise DJANGO REST FRAMEWORK , le code ci-dessous pour envoyer des e-mails était dans un ensemble de vues de modèle dans monviews.py

Donc, après avoir lu plusieurs belles réponses, c'est ce que j'ai fait.

from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives

def send_receipt_to_email(self, request):

    emailSubject = "Subject"
    emailOfSender = "email@domain.com"
    emailOfRecipient = 'xyz@domain.com'

    context = ({"name": "Gilbert"}) #Note I used a normal tuple instead of  Context({"username": "Gilbert"}) because Context is deprecated. When I used Context, I got an error > TypeError: context must be a dict rather than Context

    text_content = render_to_string('receipt_email.txt', context, request=request)
    html_content = render_to_string('receipt_email.html', context, request=request)

    try:
        #I used EmailMultiAlternatives because I wanted to send both text and html
        emailMessage = EmailMultiAlternatives(subject=emailSubject, body=text_content, from_email=emailOfSender, to=[emailOfRecipient,], reply_to=[emailOfSender,])
        emailMessage.attach_alternative(html_content, "text/html")
        emailMessage.send(fail_silently=False)

    except SMTPException as e:
        print('There was an error sending an email: ', e) 
        error = {'message': ",".join(e.args) if len(e.args) > 0 else 'Unknown Error'}
        raise serializers.ValidationError(error)

Important! Alors, comment render_to_stringobtient-on receipt_email.txtet receipt_email.html? Dans mon settings.py, j'ai TEMPLATESet voici à quoi ça ressemble

Faites attention à DIRS, il y a cette ligne os.path.join(BASE_DIR, 'templates', 'email_templates') .Cette ligne est ce qui rend mes modèles accessibles. Dans mon project_dir, j'ai un dossier appelé templateset un sous-répertoire appelé email_templatescomme ça project_dir->templates->email_templates. Mes modèles receipt_email.txtet receipt_email.htmlsont sous le sous- email_templatesrépertoire.

TEMPLATES = [
{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'templates', 'email_templates')],
    'APP_DIRS': True,
    'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
        ],
    },
},
]

Permettez-moi d'ajouter cela, mon recept_email.txtapparence ressemble à ceci;

Dear {{name}},
Here is the text version of the email from template

Et, mon receipt_email.htmlressemble à ceci;

Dear {{name}},
<h1>Now here is the html version of the email from the template</h1>

0

J'ai écrit un extrait qui vous permet d'envoyer des e-mails rendus avec des modèles stockés dans la base de données. Un exemple:

EmailTemplate.send('expense_notification_to_admin', {
    # context object that email template will be rendered with
    'expense': expense_request,
})

0

Si vous souhaitez des modèles d'e-mails dynamiques pour votre courrier, enregistrez le contenu de l'e-mail dans vos tables de base de données. C'est ce que j'ai enregistré en tant que code HTML dans la base de données =

<p>Hello.. {{ first_name }} {{ last_name }}.  <br> This is an <strong>important</strong> {{ message }}
<br> <b> By Admin.</b>

 <p style='color:red'> Good Day </p>

Selon vous:

from django.core.mail import EmailMultiAlternatives
from django.template.loader import get_template

def dynamic_email(request):
    application_obj = AppDetails.objects.get(id=1)
    subject = 'First Interview Call'
    email = request.user.email
    to_email = application_obj.email
    message = application_obj.message

    text_content = 'This is an important message.'
    d = {'first_name': application_obj.first_name,'message':message}
    htmly = FirstInterviewCall.objects.get(id=1).html_content #this is what i have saved previously in database which i have to send as Email template as mentioned above HTML code

    open("partner/templates/first_interview.html", "w").close() # this is the path of my file partner is the app, Here i am clearing the file content. If file not found it will create one on given path.
    text_file = open("partner/templates/first_interview.html", "w") # opening my file
    text_file.write(htmly) #putting HTML content in file which i saved in DB
    text_file.close() #file close

    htmly = get_template('first_interview.html')
    html_content = htmly.render(d)  
    msg = EmailMultiAlternatives(subject, text_content, email, [to_email])
    msg.attach_alternative(html_content, "text/html")
    msg.send()

Cela enverra au modèle HTML dynamique ce que vous avez enregistré dans Db.


0

send_emai()n'a pas fonctionné pour moi, donc j'ai utilisé EmailMessage ici dans les django docs .

J'ai inclus deux versions de l'anser:

  1. Avec la version e-mail html uniquement
  2. Avec les versions e-mail en texte brut et e-mail html
from django.template.loader import render_to_string 
from django.core.mail import EmailMessage

# import file with html content
html_version = 'path/to/html_version.html'

html_message = render_to_string(html_version, { 'context': context, })

message = EmailMessage(subject, html_message, from_email, [to_email])
message.content_subtype = 'html' # this is required because there is no plain text email version
message.send()

Si vous souhaitez inclure une version en texte brut de votre e-mail, modifiez ce qui précède comme ceci:

from django.template.loader import render_to_string 
from django.core.mail import EmailMultiAlternatives # <= EmailMultiAlternatives instead of EmailMessage

plain_version = 'path/to/plain_version.html' # import plain version. No html content
html_version = 'path/to/html_version.html' # import html version. Has html content

plain_message = render_to_string(plain_version, { 'context': context, })
html_message = render_to_string(html_version, { 'context': context, })

message = EmailMultiAlternatives(subject, plain_message, from_email, [to_email])
message.attach_alternative(html_message, "text/html") # attach html version
message.send()

Mes versions plain et html ressemblent à ceci: plain_version.html:

Plain text {{ context }}

html_version.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 ...
 </head>
<body>
<table align="center" border="0" cellpadding="0" cellspacing="0" width="320" style="border: none; border-collapse: collapse; font-family:  Arial, sans-serif; font-size: 14px; line-height: 1.5;">
...
{{ context }}
...
</table>
</body>
</html>

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.