前置条件
邮箱需要开启SMTP功能
简单了解
SMTP(Simple Mail Transfer Protocol)
简单邮件传输协议, 是电子邮件发送的行业标准协议.(发送用)
IMAP(Internet Access Message Protocol)
处理从接收服务器管理和检索电子邮件消息的电子邮件协议.(接受用)
可以跨所有设备同步消息.
POP3
POP(邮局协议), 3(版本号), 也是接受用的协议.
和IMAP
主要区别在, POP3
会保存文件到本地, 服务器删了也没事, 便于脱机.
开启SMTP
以 outlook 邮箱为例:
注: 其它类型的邮箱大多需要获取授权码才能登录邮箱, 而outlook
用账号密码就可以.
简单实现
先介绍要用到的库
- smtplib
定义了SMTP客户端的使用
- email
邮件的编写和简单发送
import smtplib from email.message import EmailMessage
msg = EmailMessage() msg['From'] = 'me@outlook.com' msg['To'] = ['example@outlook.com', 'example@qq.com'] password = '*****'
msg['Subject'] = 'This is a test email' msg.set_content('Hello !')
with smtplib.SMTP('smtp.office365.com', port=587) as smtp: smtp.starttls() smtp.login(msg['From'], password) smtp.send_message(msg)
|
当出现更复杂的需求出现时, 上面的代码很显然不够便捷, 这时要不就自己封装一个库, 要不就找找有没有现成的, 而redmail
就是一个不错的选择.
redmail 库
一个高级邮件发送库, 可以快速简易的进行邮件发送.
官方文档 -> 🚪
安装
例子
from redmail import EmailSender
email = EmailSender(host='smtp.office365.com', port=587, username='me@outlook.com', password='*****')
email.send( subject='This is a test email', sender='me@outlook.com', receivers=['example@outlook.com', 'example@qq.com'], text='Hello!' )
|
一键群发
大致流程
现在有这么一个需求:
截图到剪贴板->粘贴到邮件客户端->填写收件人->点击发送->关闭客户端
|
我们把它优化成这样:
构建配置
先定义一下配置文件config/email_archive.yml
, 有不同需求时可以通过切换配置文件来快速应用.
smtp: username: me@outlook.com password: host: smtp.office365.com port: 587
send: sender: owq<me@outlook.com> receive: - example01@outlook.com cc: - example02@outlook.com - example03@outlook.com bcc: - example04@outlook.com - example05@outlook.com
|
加载yml
文件用的函数
import yaml
def load_yml(conf_path:str) -> dict: """Load .yml file """ with open(file=conf_path, mode='r', encoding="utf-8") as f: return yaml.load(stream=f, Loader=yaml.FullLoader)
|
图片提取
使用PIL
库从剪贴板提取图片保存
from PIL import Image, ImageGrab
def save_paste_pic(filename: str) -> bool: """ Save the clipboard picture """ im = ImageGrab.grabclipboard() if isinstance(im, Image.Image): im.save(filename) return True return False
|
注: Mac 桌面环境暂不支持
密文密码
对于不想把密码保存在配置里的情况, 这里可以定义一个模拟密码输入的函数.
import msvcrt
def input_password(info: str = 'Password: ') -> tuple: """shell密码输入
按键绑定: 回车确认, 退格删除, Esc/Ctrl+C 退出(信号为False)
:param info: 输入提示信息, defaults to 'Password: ' :return: 信号和输入密码 :rtype: tuple """ print(info, end='', flush=True) pawd_arr, sing = [], False while True:
keypad = msvcrt.getch() if keypad == b'\r': msvcrt.putch(b'\n') sing = True break elif keypad in [b'\x1b', b'\x03']: msvcrt.putch(b'\n') break elif keypad == b'\x08': if pawd_arr: pawd_arr.pop() msvcrt.putch(b'\b') msvcrt.putch(b' ') msvcrt.putch(b'\b') else: pawd_arr.append(keypad) msvcrt.putch(b'*')
return sing, b''.join(pawd_arr).decode()
|
↓ 效果是这样子 ↓
![]()
注: 仅适用 Windows 桌面环境
封装函数
创建templates\archive_pic.html
编写内容模板, 便于邮件内容修改.
<h1>Archive</h1> {{ pic }}
|
定义下发送邮件的函数
def send_archive_email(conf: dict, img_path: str): """加载配置发送附加图片的归档邮件
:param conf: 发送配置 :param img_path: 发送图片路径 """ email = EmailSender(**conf['smtp']) email.set_template_paths(html='templates') try: email.send( **conf['send'], subject=f"Recorded in {time.strftime('%b %d, %Y', time.localtime())}", html_template='archive_pic.html', body_images={'pic': img_path}, ) print('Email send done.') except smtplib.SMTPAuthenticationError: print('Authentication unsuccessful.') except smtplib.SMTPDataError: print('SMTP service exception, login authentication is required.')
|
接下来编写一下流程, 就基本完成了~
def main(): """ 获取剪贴板图片添加到邮件发送 """
img_path = r'paste_pic.png' if save_paste_pic(img_path):
conf = load_yml(r'config/email_archive.yml') if not conf['smtp']['password']: sign, password = input_password() if sign: conf['smtp']['password'] = password else: return
send_archive_email(conf, img_path) else: print('Clipboard has no pictures!')
|
快速启动
这里使用的是PowerShell
, 打开它的配置文件(没有需要创建).
创建运行函数和别名
function sendArchiveEmail { $Pwd = Get-Location Write-Output 'Start send_archive_email.py.' cd D:\Project\auto_email && python send_archive_email.py cd $Pwd }
New-Alias send-email sendArchiveEmail
|
刷新终端后使用send-email
命令就可以启动脚本了
![]()