Membuat templat email dengan Django

207

Saya ingin mengirim email-HTML, menggunakan templat Django seperti ini:

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

Saya tidak dapat menemukan apa pun tentangnya send_mail, dan Django-mailer hanya mengirim templat HTML, tanpa data dinamis.

Bagaimana cara saya menggunakan mesin template Django untuk menghasilkan email?

Anakin
sumber
3
Perhatikan 1.7penawaran Django html_messagedi send_email stackoverflow.com/a/28476681/953553
andilabs
Hai @ anakin, saya sudah lama berjuang dengan masalah ini dan memutuskan untuk membuat paket untuk itu. Saya akan sangat senang mendapatkan tanggapan Anda: github.com/charlesthk/django-simple-mail
Charlesthk

Jawaban:

385

Dari dokumen , untuk mengirim email HTML Anda ingin menggunakan tipe konten alternatif, seperti ini:

from django.core.mail import EmailMultiAlternatives

subject, from_email, to = 'hello', '[email protected]', '[email protected]'
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()

Anda mungkin ingin dua templat untuk surel Anda - satu templat teks polos yang terlihat seperti ini, disimpan di direktori templat di bawah email.txt:

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

dan yang HTMLy, disimpan di bawah email.html:

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

Anda kemudian dapat mengirim email menggunakan kedua templat tersebut dengan memanfaatkan get_template, seperti ini:

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', '[email protected]', '[email protected]'
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()
Dominic Rodger
sumber
40
Saya pikir Anda dapat menyederhanakan ini dengan render_to_string , yang akan membiarkan Anda kehilangan baris terpisah yang menetapkan templat ke plaintextdan htmly, dan hanya mengatur templat dan konteks ketika Anda mendefinisikan text_contentdan html_content.
cms_mgr
@cms_mgr Bisakah Anda menguraikan apa yang ingin Anda katakan dan bagaimana kami dapat menggunakannya
akki
3
@akki lihat jawaban andi di bawah ini, yang juga menyederhanakan bagian alternatif berkat param html_message yang ditambahkan ke send_email () di Django 1.7
Mike S
Maafkan saya tetapi mengapa kita menggunakan txt dan htmly keduanya sekaligus untuk surat. Saya tidak mendapatkan logika ini
Shashank Vivek
mereka hanya contoh untuk menunjukkan berbagai jenis metode, Anda dapat menggunakan salah satu dari mereka @ShashankVivek
erdemlal
242

Anak laki-laki dan anak perempuan!

Sejak Django 1.7 dalam metode send_emailhtml_message parameter ditambahkan.

html_message: Jika html_message disediakan, email yang dihasilkan akan berupa email multipart / alternatif dengan pesan sebagai teks / tipe konten biasa dan html_message sebagai tipe konten teks / html.

Jadi Anda bisa:

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,
    '[email protected]',
    ['[email protected]'],
    html_message=msg_html,
)
andilab
sumber
1
Perhatikan jika 'email.txt' dan 'email.html' berada dalam templat direktori sebagaimana ditentukan dalam pengaturan daripada hanya melakukan render_to_string ('email.txt', {'some_params': some_params}:
Bruno Vermeulen
Terima kasih atas render_to_stringpetunjuknya, sangat berguna.
hoefling
1
Solusi bagus! Namun, dengan send_mailtidak mungkin untuk mengatur beberapa tajuk khusus seperti misalnya Return-Pathyang dapat diatur denganEmailMultiAlternatives's constructor header parameter
Qlimax
26

Saya telah membuat django-templated-email dalam upaya untuk menyelesaikan masalah ini, terinspirasi oleh solusi ini (dan kebutuhan untuk, di beberapa titik, beralih dari menggunakan templat Django ke menggunakan mailchimp dll. Set templat untuk transaksional, templated email untuk proyek saya sendiri). Ini masih dalam proses, tetapi untuk contoh di atas, Anda akan melakukan:

from templated_email import send_templated_mail
send_templated_mail(
        'email',
        '[email protected]',
        ['[email protected]'],
        { 'username':username }
    )

Dengan tambahan berikut ini ke settings.py (untuk melengkapi contoh):

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

Ini akan secara otomatis mencari templat bernama 'templated_email / email.txt' dan 'templated_email / email.html' untuk masing-masing bagian html dan polos, di dir / loader template django normal (mengeluh jika tidak dapat menemukan setidaknya salah satu dari mereka) .

Darb
sumber
1
Terlihat bagus untukku. Saya telah memangkas ini dan melemparkannya ke tiket untuk menambahkan django.shortcuts.send_templated_mail: code.djangoproject.com/ticket/17193
Tom Christie
Keren, senang melihatnya diajukan sebagai alat untuk inti Django. Use-case / focus saya untuk lib sedikit lebih besar dari sekedar pintasan, (mudah beralih di antara penyedia surat yang memiliki kunci / nilai api untuk pengiriman surat), tetapi rasanya seperti fitur yang hilang dari inti
Darb
15

Gunakan EmailMultiAlternatives dan render_to_string untuk memanfaatkan dua templat alternatif (satu dalam teks biasa dan satu dalam 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 = ['[email protected]']
email.send()
Rick Westera
sumber
5

Saya telah membuat Django Simple Mail untuk memiliki templat yang sederhana, dapat disesuaikan dan dapat digunakan kembali untuk setiap email transaksional yang ingin Anda kirim.

Konten dan templat email dapat diedit langsung dari admin django.

Dengan contoh Anda, Anda akan mendaftarkan email Anda:

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)

Dan kirimkan dengan cara ini:

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)

Saya ingin sekali mendapat tanggapan.

Charlesthk
sumber
Akan sangat membantu jika Anda mengunggah aplikasi demo paket Anda di repo Anda.
ans2human
Hai @ ans2human terima kasih atas saran ini, saya menambahkannya ke daftar perbaikan!
Charlesthk
3

Ada kesalahan dalam contoh .... jika Anda menggunakannya sebagai tertulis, kesalahan berikut terjadi:

<type 'exceptionions.Exception'>: objek 'dict' tidak memiliki atribut 'render_context'

Anda perlu menambahkan impor berikut:

from django.template import Context

dan ubah kamus menjadi:

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

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

idbill
sumber
Terima kasih - ini sudah diperbaiki sekarang.
Dominic Rodger
3

Django Mail Templated adalah aplikasi Django yang kaya fitur untuk mengirim email dengan sistem template Django.

Instalasi:

pip install django-mail-templated

Konfigurasi:

INSTALLED_APPS = (
    ...
    'mail_templated'
)

Templat:

{% 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])

Info lebih lanjut: https://github.com/artemrizhov/django-mail-templated

raacer
sumber
Ini sangat mudah digunakan. Terima kasih.
cheenbabes
Hai, bagaimana saya bisa mengatur semua penerima saya ke BCC?
aldesabido
@aldesabido Ini hanya pembungkus kelas EmailMessage standar Django. Jadi, Anda harus membaca dokumentasi resmi ketika mencari fitur-fitur seperti: docs.djangoproject.com/en/1.10/topics/email Juga lihat pertanyaan serupa: stackoverflow.com/questions/3470172/…
raacer
Untuk lebih tepatnya, EmailMessage standar tidak dibungkus, tetapi diwarisi. Yaitu ini adalah ekstensi untuk kelas standar :)
raacer
Dimungkinkan untuk memasukkan JS / CSS dalam templat?
Daniel Shatz
3

Saya tahu ini adalah pertanyaan lama, tetapi saya juga tahu bahwa beberapa orang sama seperti saya dan selalu mencari jawaban yang uptodate , karena jawaban lama terkadang dapat memiliki informasi yang sudah usang jika tidak diperbarui.

Sekarang Januari 2020, dan saya menggunakan Django 2.2.6 dan Python 3.7

Catatan: Saya menggunakan DJANGO REST FRAMEWORK , kode di bawah ini untuk mengirim email menggunakan model viewset diviews.py

Jadi setelah membaca beberapa jawaban yang bagus, inilah yang saya lakukan.

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 protected]"
    emailOfRecipient = '[email protected]'

    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)

Penting! Jadi bagaimana render_to_stringmendapatkan receipt_email.txtdan receipt_email.html? Di saya settings.py, saya punya TEMPLATESdan di bawah ini adalah tampilannya

Perhatikan DIRS, ada baris ini os.path.join(BASE_DIR, 'templates', 'email_templates') . Baris ini yang membuat templat saya dapat diakses. Dalam project_dir saya, saya memiliki folder bernama templates, dan sub_directory dipanggil email_templatesseperti ini project_dir->templates->email_templates. Templat saya receipt_email.txtdan receipt_email.htmlberada di bawah email_templatessubdirektori.

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',
        ],
    },
},
]

Biarkan saya tambahkan saja, recept_email.txtpenampilan saya seperti ini;

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

Dan, receipt_email.htmlpenampilan saya seperti ini;

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

Saya menulis cuplikan yang memungkinkan Anda mengirim email yang diberikan dengan templat yang disimpan dalam database. Sebuah contoh:

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

Jika Anda ingin templat email dinamis untuk surel Anda maka simpan konten surel dalam tabel basis data Anda. Ini yang saya simpan sebagai kode HTML di database =

<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>

Menurut pandangan Anda:

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()

Ini akan mengirimkan template HTML dinamis apa yang telah Anda simpan di Db.

Javed
sumber
0

send_emai()tidak bekerja untuk saya jadi saya gunakan EmailMessage di sini di django docs .

Saya telah memasukkan dua versi anser:

  1. Dengan versi email html saja
  2. Dengan email teks biasa dan versi email 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()

Jika Anda ingin memasukkan versi teks biasa dari email Anda, ubah yang di atas seperti ini:

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()

Versi html dan polos saya terlihat seperti ini: 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>
alkadelik
sumber