当前位置: 首页 > news >正文

[Django 0-1] Core.Email 模块

Mail 源码分析

模块文件结构

.
├── __init__.py
├── backends
│   ├── __init__.py
│   ├── base.py
│   ├── console.py
│   ├── dummy.py
│   ├── filebased.py
│   ├── locmem.py
│   └── smtp.py
├── message.py
└── utils.py

模块结构

  • backends: 邮件后端,包括 console,dummy,filebased,localmem,smtp
  • message: 主要是消息的抽象,分为 plaintext,html 两类

ConsoleEmailBackend 类

属性
  1. stream: 输出流
方法
  1. send_messages(email_messages): 发送邮件
def write_message(self, message):msg = message.message()msg_data = msg.as_bytes()charset = (msg.get_charset().get_output_charset() if msg.get_charset() else "utf-8")msg_data = msg_data.decode(charset)self.stream.write("%s\n" % msg_data)self.stream.write("-" * 79)self.stream.write("\n")def send_messages(self, email_messages):"""Write all messages to the stream in a thread-safe way."""if not email_messages:returnmsg_count = 0with self._lock:try:stream_created = self.open()for message in email_messages:self.write_message(message)self.stream.flush()  # flush after each messagemsg_count += 1if stream_created:self.close()except Exception:if not self.fail_silently:raisereturn msg_count

DummyEmailBackend 类

可以用于本地测试,验证方法调用是否成功

方法
  1. send_messages(email_messages): 发送邮件
def send_messages(self, email_messages):return len(list(email_messages))

FileBasedEmailBackend 类

文件流,将邮件消息写入文件流中

方法
  1. send_messages(email_messages): 发送邮件
def write_message(self, message):self.stream.write(message.message().as_bytes() + b"\n")self.stream.write(b"-" * 79)self.stream.write(b"\n")

LocmemEmailBackend 类

内存中存储邮件消息,可以用于测试或开发

方法
  1. send_messages(email_messages): 发送邮件
def send_messages(self, messages):"""Redirect messages to the dummy outbox"""msg_count = 0for message in messages:  # .message() triggers header validationmessage.message()mail.outbox.append(copy.deepcopy(message))msg_count += 1return msg_count

SMTPEmailBackend 类

SMTP 邮件后端,通过 SMTP 协议发送邮件

方法
  1. send_messages(email_messages): 发送邮件
def send_messages(self, email_messages):"""Send one or more EmailMessage objects and return the number of emailmessages sent."""if not email_messages:return 0with self._lock:new_conn_created = self.open()if not self.connection or new_conn_created is None:# We failed silently on open().# Trying to send would be pointless.return 0num_sent = 0try:for message in email_messages:sent = self._send(message)if sent:num_sent += 1finally:if new_conn_created:self.close()return num_sent

EmailMessage 类

属性
  1. subject:邮件主题
  2. body:邮件正文
  3. from_email:发件人地址
  4. to:收件人地址列表
  5. cc:抄送人地址列表
  6. bcc: 密送人地址列表
  7. reply_to:回复地址列表
  8. headers:自定义邮件头
  9. attachments:附件列表
  10. connection: 邮件服务器
方法
  1. attach(): 添加附件

邮件附件如果已经是 mime.MIMEBase 的话,直接加入到附件列表中。
如果不是,先猜测 mimetype 类型,然后以(filename, content, mimetype)加入到附件列表中。

filename=None, mimetype=None 的情况,会出错。


def attach(self, filename=None, content=None, mimetype=None):"""Attach a file with the given filename and content. The filename canbe omitted and the mimetype is guessed, if not provided.If the first parameter is a MIMEBase subclass, insert it directlyinto the resulting message attachments.For a text/* mimetype (guessed or specified), when a bytes object isspecified as content, decode it as UTF-8. If that fails, set themimetype to DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content."""if isinstance(filename, MIMEBase):if content is not None or mimetype is not None:raise ValueError("content and mimetype must not be given when a MIMEBase ""instance is provided.")self.attachments.append(filename)elif content is None:raise ValueError("content must be provided.")else:mimetype = (mimetypeor mimetypes.guess_type(filename)[0]or DEFAULT_ATTACHMENT_MIME_TYPE)basetype, subtype = mimetype.split("/", 1)if basetype == "text":if isinstance(content, bytes):try:content = content.decode()except UnicodeDecodeError:# If mimetype suggests the file is text but it's# actually binary, read() raises a UnicodeDecodeError.mimetype = DEFAULT_ATTACHMENT_MIME_TYPEself.attachments.append((filename, content, mimetype))
  1. message(): 生成 MIMEText 对象
def message(self):encoding = self.encoding or settings.DEFAULT_CHARSETmsg = SafeMIMEText(self.body, self.content_subtype, encoding)msg = self._create_message(msg)msg["Subject"] = self.subjectmsg["From"] = self.extra_headers.get("From", self.from_email)self._set_list_header_if_not_empty(msg, "To", self.to)self._set_list_header_if_not_empty(msg, "Cc", self.cc)self._set_list_header_if_not_empty(msg, "Reply-To", self.reply_to)# Email header names are case-insensitive (RFC 2045), so we have to# accommodate that when doing comparisons.header_names = [key.lower() for key in self.extra_headers]if "date" not in header_names:# formatdate() uses stdlib methods to format the date, which use# the stdlib/OS concept of a timezone, however, Django sets the# TZ environment variable based on the TIME_ZONE setting which# will get picked up by formatdate().msg["Date"] = formatdate(localtime=settings.EMAIL_USE_LOCALTIME)if "message-id" not in header_names:# Use cached DNS_NAME for performancemsg["Message-ID"] = make_msgid(domain=DNS_NAME)for name, value in self.extra_headers.items():if name.lower() != "from":  # From is already handledmsg[name] = valuereturn msg

EmailMultiAlternatives 类

EmailMultiAlternatives 类继承自 EmailMessage 类,增加了对 HTML 格式的支持。

总结

Django 的邮件模块提供了多种邮件后端,可以根据需要选择不同的后端。留有 dummy,console,locmem,filebased,smtp 多种类型后端。
通过 Django 邮件模块,避免重复编码,针对各类邮件服务器的特定规则只需自己实现发送后端逻辑,不需要重头编写。

相关文章:

  • MacOS安装Homebrew教程
  • 力扣---完全平方数
  • iOS常见崩溃简介
  • VR历史建筑漫游介绍|虚拟现实体验店|VR设备购买
  • #Linux(帮助手册)
  • Oracle锁表解决方案
  • 计算机网络——物理层(信道复用技术)
  • Python Web开发记录 Day13:Django part7 Ajax入门与案例(任务管理)
  • 两台电脑简单的通信过程详解(局域网,同网段)
  • 【爬虫】web自动化和接口自动化
  • 【全栈老魏】Vue3引入echarts
  • gin | gin环境搭建与示例工程
  • spring-boot-devtools debug SilentExitException
  • 全栈的自我修养 ———— 微信小程序开发电脑测试api请求正常,移动端请求异常!!
  • 安卓性能优化面试题 35-40
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • CSS相对定位
  • css属性的继承、初识值、计算值、当前值、应用值
  • Docker: 容器互访的三种方式
  • echarts花样作死的坑
  • Fundebug计费标准解释:事件数是如何定义的?
  • Git 使用集
  • HTTP 简介
  • IP路由与转发
  • JavaScript的使用你知道几种?(上)
  • Java方法详解
  • Java新版本的开发已正式进入轨道,版本号18.3
  • Spring核心 Bean的高级装配
  • yii2中session跨域名的问题
  • 对象管理器(defineProperty)学习笔记
  • 分享一份非常强势的Android面试题
  • 复杂数据处理
  • 好的网址,关于.net 4.0 ,vs 2010
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 力扣(LeetCode)965
  • 前端技术周刊 2019-01-14:客户端存储
  • 前端技术周刊 2019-02-11 Serverless
  • 想使用 MongoDB ,你应该了解这8个方面!
  • 责任链模式的两种实现
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • #QT项目实战(天气预报)
  • #ubuntu# #git# repository git config --global --add safe.directory
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (论文阅读30/100)Convolutional Pose Machines
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (转)C#调用WebService 基础
  • (转)shell调试方法
  • (转载)(官方)UE4--图像编程----着色器开发
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .chm格式文件如何阅读
  • .net FrameWork简介,数组,枚举
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET 的程序集加载上下文
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试