如何在Django中编写支持变量列表的HTML邮件发送函数
问题原因&解决方案
错误原因
你遇到的报错是因为str.format()的用法完全错误,同时你的实现逻辑绕开了Django模板渲染的原生能力,属于多此一举:
- 字符串是不可变类型,你在循环中执行
html_message.format(variable)不会修改原变量,返回的新字符串没有被接收赋值 - 如果你HTML模板中写了
{0}、{1}这类占位符,format需要一次性传入所有占位符对应的参数,你循环每次只传1个参数,自然会出现索引超出范围的报错 - 你调用
render_to_string的时候只传入了固定的{'context': 'values'},没有把你实际需要的变量传入模板渲染,额外用format属于完全不必要的操作。
最优实现方案(推荐)
直接用Django模板引擎的原生渲染能力,传入变量字典渲染模板,不需要额外的格式化步骤,变量可读性和可维护性更高:
第一步:修改发送函数
from django.core.mail import send_mail from django.template.loader import render_to_string from django.core.mail import get_connection from django.utils.html import strip_tags from otr import settings def send_email(subject, email_template, recipient, username, password, context): # 直接把变量字典传入render_to_string完成模板渲染 html_message = render_to_string(email_template, context) plain_message = strip_tags(html_message) with get_connection( host=settings.EMAIL_HOST, port=settings.EMAIL_PORT, username=username, password=password, use_tls=True ) as connection: send_mail(subject, plain_message, 'Me', [recipient], fail_silently=False, html_message=html_message, connection=connection)
第二步:调整模板写法
你的HTML邮件模板(比如emails/followup_email.html)直接用Django模板语法写变量即可,示例:
<p>尊敬的{{ customer_name }}:</p> <p>您好!我是{{ dear_user }}</p> <p>我的联系电话是{{ phone_number }}</p> <p>此致</p> <p>{{ sincerely_user }}</p>
第三步:调用方式调整
调用时把变量组装成字典传入即可:
subject = "My subject" email_template = "emails/followup_email.html" recipient = queryset.customer_email username = username_variable password = password_variable # 直接组装变量字典 context = { "customer_name": "Bob", "dear_user": "my_name", "phone_number": "1111111111", "sincerely_user": "my_name" } send_email(subject, email_template, recipient, username, password, context)
兼容原有列表传参的方案(不推荐)
如果你一定要保留原有传变量列表的写法,也可以修改渲染逻辑,不要循环调用format,一次性解包列表传入即可:
def send_email(subject, email_template, recipient, username, password, variable_list): html_message = render_to_string(email_template, {}) # 一次性解包所有变量传入format,接收返回的新字符串 html_message = html_message.format(*variable_list) plain_message = strip_tags(html_message) with get_connection( host=settings.EMAIL_HOST, port=settings.EMAIL_PORT, username=username, password=password, use_tls=True ) as connection: send_mail(subject, plain_message, 'Me', [recipient], fail_silently=False, html_message=html_message, connection=connection)
注意这种写法需要你模板中的{0}、{1}这类占位符的数量和顺序,和variable_list的长度、顺序完全对应,否则会报错或渲染错误。
内容的提问来源于stack exchange,提问作者Thomas166
相关产品推荐
相关产品推荐

