Tạo mẫu email với Django


205

Tôi muốn gửi email HTML, sử dụng các mẫu Django như thế này:

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

Tôi không thể tìm thấy bất cứ điều gì send_mailvà django-mailer chỉ gửi các mẫu HTML, không có dữ liệu động.

Làm cách nào để sử dụng công cụ mẫu của Django để tạo e-mail?


3
Thông báo Django 1.7cung cấp html_messagetrong send_email stackoverflow.com/a/28476681/953553
andilabs

Xin chào @anakin, tôi đã vật lộn với vấn đề này trong một thời gian dài và quyết định tạo ra một gói cho nó. Tôi sẽ rất vui khi nhận được phản hồi của bạn: github.com/charlesthk/django-simple-mail
Charlesthk

Câu trả lời:


384

Từ các tài liệu , để gửi e-mail HTML bạn muốn sử dụng các loại nội dung thay thế, như thế này:

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

Bạn có thể muốn có hai mẫu cho e-mail của mình - một mẫu văn bản đơn giản trông giống như thế này, được lưu trữ trong thư mục mẫu của bạn bên dưới email.txt:

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

và một HTMLy, được lưu trữ dưới email.html:

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

Sau đó, bạn có thể gửi e-mail bằng cả hai mẫu đó bằng cách sử dụng get_template, như thế này:

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
Tôi nghĩ rằng bạn có thể đơn giản hóa điều này với render_to_opes , điều này sẽ cho phép bạn mất các dòng riêng biệt gán các mẫu cho plaintexthtmly, và chỉ đặt các mẫu và bối cảnh khi bạn xác định text_contenthtml_content.
cms_mgr

@cms_mgr Bạn có thể nói rõ hơn những gì bạn muốn nói và làm thế nào chúng ta có thể sử dụng nó
akki

3
@akki xem câu trả lời của Andi dưới đây, cũng đơn giản hóa phần thay thế nhờ html_message param được thêm vào send_email () trong Django 1.7
Mike S

Xin lỗi tôi nhưng tại sao chúng tôi sử dụng txt và htmly cả hai cùng một lúc cho một thư. Tôi không hiểu logic này
Shashank Vivek

chúng chỉ là ví dụ để hiển thị các loại phương thức khác nhau, bạn có thể sử dụng bất kỳ phương pháp nào trong số chúng @ShashankVivek
erdemlal

241

Bé trai và bé gái!

Vì phương thức send_email 1.7 của Django, html_messagetham số đã được thêm vào.

html_message: Nếu html_message được cung cấp, email kết quả sẽ là một email nhiều phần / thay thế với thông điệp là loại nội dung văn bản / đơn giản và html_message là loại nội dung văn bản / html.

Vì vậy, bạn có thể chỉ:

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
Lưu ý nếu 'email.txt' và 'email.html' nằm trong các mẫu thư mục như được xác định trong cài đặt thay vì chỉ render_to_opes ('email.txt', {'some_params': some_params} _
Bruno Vermeulen

Cảm ơn các render_to_stringgợi ý, rất tiện dụng.
cuốc vào

1
Giải pháp tốt! Tuy nhiên, send_mailkhông thể đặt một số tiêu đề tùy chỉnh như tức là Return-Pathcó thể được đặt bằngEmailMultiAlternatives's constructor header parameter
Qlimax

26

Tôi đã tạo ra django-templated-email trong một nỗ lực để giải quyết vấn đề này, lấy cảm hứng từ giải pháp này (và đôi khi, cần phải chuyển từ sử dụng các mẫu django sang sử dụng một mailchimp, vv các bộ mẫu cho các email giao dịch, templated cho dự án của riêng tôi). Đây vẫn là một công việc đang tiến triển, nhưng với ví dụ trên, bạn sẽ làm:

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

Với việc bổ sung các phần sau vào settings.py (để hoàn thành ví dụ):

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

Điều này sẽ tự động tìm kiếm các mẫu có tên 'templated_email / email.txt' và 'templated_email / email.html' cho các phần đơn giản và html tương ứng, trong các thư mục / trình tải mẫu django bình thường (phàn nàn nếu nó không thể tìm thấy ít nhất một trong số đó) .


1
Co vẻ tôt vơi tôi. Tôi đã cắt nó xuống và ném nó vào một vé để thêm django.shortcuts.send_templated_mail: code.djangoproject.com/ticket/17193
Tom Christie

Thật tuyệt, rất vui khi thấy nó được đề xuất như một công cụ cho lõi django. Ca sử dụng / tiêu điểm của tôi cho lib lớn hơn một chút so với phím tắt, (dễ dàng chuyển đổi giữa các nhà cung cấp thư có khóa / giá trị api để gửi thư), nhưng nó có cảm giác như một tính năng bị thiếu trong lõi
Darb

15

Sử dụng EmailMultiAlternigin và render_to_opes để sử dụng hai mẫu thay thế (một trong văn bản thuần túy và một trong 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

Tôi đã tạo Django Simple Mail để có một mẫu đơn giản, có thể tùy chỉnh và có thể sử dụng lại cho mỗi email giao dịch bạn muốn gửi.

Nội dung và mẫu email có thể được chỉnh sửa trực tiếp từ quản trị viên của django.

Với ví dụ của bạn, bạn sẽ đăng ký email của mình:

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)

Và gửi nó theo cách này:

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)

Tôi rất thích nhận được bất kỳ thông tin phản hồi.


Nó sẽ giúp ích rất nhiều nếu bạn tải lên một ứng dụng demo của gói trên repo của bạn.
ans2human

Xin chào @ ans2human cảm ơn về đề xuất này, tôi thêm nó vào danh sách các cải tiến!
Charlerak

3

Có một lỗi trong ví dụ .... nếu bạn sử dụng nó như được viết, lỗi sau xảy ra:

<gõ 'ngoại lệ. Ngoại lệ'>: đối tượng 'dict' không có thuộc tính 'render_context'

Bạn sẽ cần thêm nhập sau:

from django.template import Context

và thay đổi từ điển thành:

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

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


Cảm ơn - điều này đã được sửa bây giờ.
Dominic Rodger

3

Django Mail Templated là một ứng dụng Django giàu tính năng để gửi email với hệ thống mẫu Django.

Cài đặt:

pip install django-mail-templated

Cấu hình:

INSTALLED_APPS = (
    ...
    'mail_templated'
)

Bản mẫu:

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

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

Con trăn

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

Thông tin thêm: https://github.com/artemrizhov/django-mail-templated


Điều này thực sự dễ sử dụng. Cảm ơn.
cheenbabes

Xin chào, làm cách nào tôi có thể đặt tất cả người nhận của mình thành BCC?
aldesabido

@aldesabido Đây chỉ là một trình bao bọc xung quanh lớp EmailMessage tiêu chuẩn của Django. Vì vậy, bạn nên đọc tài liệu chính thức khi tìm kiếm các tính năng như vậy: docs.djangoproject.com/en/1.10/topics/email Cũng hãy xem câu hỏi tương tự: stackoverflow.com/questions/3470172/
trộm

Nói chính xác hơn, EmailMessage tiêu chuẩn không được gói mà được kế thừa. Tức là đây là phần mở rộng cho lớp tiêu chuẩn :)
raacer

Có thể bao gồm JS / CSS trong mẫu?
Daniel Shatz

3

Tôi biết đây là một câu hỏi cũ, nhưng tôi cũng biết rằng một số người cũng giống như tôi và luôn tìm kiếm câu trả lời lạc quan , vì câu trả lời cũ đôi khi có thể bị mất thông tin nếu không được cập nhật.

Bây giờ là tháng 1 năm 2020 và tôi đang sử dụng Django 2.2.6 và Python 3.7

Lưu ý: Tôi sử dụng DJANGO REST FRAMEWORK , mã bên dưới để gửi email nằm trong chế độ xem mô hình trong tôiviews.py

Vì vậy, sau khi đọc nhiều câu trả lời hay, đây là những gì tôi đã làm.

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)

Quan trọng! Vậy làm thế nào để render_to_stringcó được receipt_email.txtreceipt_email.html? Trong tôi settings.py, tôi có TEMPLATESvà bên dưới là nó trông như thế nào

Hãy chú ý DIRS, có dòng os.path.join(BASE_DIR, 'templates', 'email_templates') này. Dòng này là những gì làm cho mẫu của tôi có thể truy cập được. Trong project_dir của tôi, tôi có một thư mục được gọi templatesvà thư mục con được gọi email_templatesnhư thế này project_dir->templates->email_templates. Mẫu của tôi receipt_email.txtreceipt_email.htmlnằm dưới thư mục email_templatescon.

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

Hãy để tôi thêm rằng, recept_email.txttrông tôi như thế này;

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

Và, receipt_email.htmlngoại hình của tôi như thế này;

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

0

Tôi đã viết một đoạn mã cho phép bạn gửi email được kết xuất với các mẫu được lưu trữ trong cơ sở dữ liệu. Một ví dụ:

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

0

Nếu bạn muốn các mẫu email động cho thư của mình thì hãy lưu nội dung email trong các bảng cơ sở dữ liệu của bạn. Đây là những gì tôi đã lưu dưới dạng mã HTML trong cơ sở dữ liệu =

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

Theo quan điểm của bạn:

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

Điều này sẽ gửi mẫu HTML động những gì bạn đã lưu trong Db.


0

send_emai()không làm việc cho tôi vì vậy tôi đã sử dụng EmailMessage ở đây trong tài liệu django .

Tôi đã bao gồm hai phiên bản của anser:

  1. Chỉ với phiên bản email html
  2. Với phiên bản email văn bản và email html đơn giản
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()

Nếu bạn muốn bao gồm một phiên bản văn bản đơn giản của email của bạn, hãy sửa đổi như trên:

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

Các phiên bản đơn giản và html của tôi trông như thế này: 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>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.