一、前期设置
批量发送邮件之间需要做一下设置(腾讯企业邮箱举例)
点击设置
开启服务
生成专用密码(后续发送邮件时需要用这个密码),如果之前没有绑定微信,需要先绑定微信才能生成专用密码。
以上过程都需要点击左下角的保存设置
二、发送邮件
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
smtp_server = 'smtp.example.com' # 例如: 'smtp.gmail.com'
smtp_port = 587 # 对于Gmail,通常是587;对于其他服务,可能是25或465
#上面两个需要根据你使用的邮箱自己设置
username = 'your_email@example.com'
password = 'your_password'#专用密码
def send_email(to_email, subject, body):
msg = MIMEMultipart() # 创建邮件对象
msg['From'] = username # 发件人
msg['To'] = to_email # 收件人
msg['Subject'] = subject # 邮件主题
msg.attach(MIMEText(body, 'plain')) # 邮件正文,'plain'表示纯文本格式,也可以是'html'
try:
# 连接到SMTP服务器并发送邮件
with smtplib.SMTP(smtp_server, smtp_port) as server:
server.starttls() # 启用TLS安全传输
server.login(username, password)
server.sendmail(username, to_email, msg.as_string())
print(f"Email sent to {to_email}")
except Exception as e:
print(f"Failed to send email to {to_email}: {e}")
三、正文发送图片
在第二步的基础上升级,就是在正文中添加图片
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.header import Header
# 收件人列表
recipients = ['************@qq.com']
# 发件人信息
sender = '********@ahyec.com'
password = '**********' # 使用授权码而非密码
smtp_server = 'smtp.exmail.qq.com'
port = 465 # 使用SSL端口,如果是TLS则为587
# 邮件内容
subject = '今天真的是个好日子'
body = '该怎么申请读你的硕士呢'
image_path='3a2b1c08478dfbe4ba32db43cc5791d.png'
msg=MIMEMultipart()
# 创建邮件对象
msg_text = MIMEText(body,'html','utf-8')
msg.attach(msg_text)
#嵌入图片
with open(image_path,'rb') as f:
image_data=f.read()
image=MIMEImage(image_data,name=image_path)
image.add_header('Content-ID','<image1>')
# image.add_header('Content-Disposition', 'inline')
msg.attach(image)
html = f"""
<html>
<body>
<img src="cid:image1" alt="产品图" style="display:block; width:600px; max-width:100%;"> <!-- 使用Content-ID引用图片 -->
</body>
</html>
"""
msg.attach(MIMEText(html,'html','utf-8'))
#设置发送人和主题
msg['From'] = Header("**********@ahyec.com")
# msg['To'] = Header("**********@qq.com", 'utf-8')
msg['Subject'] = Header(subject, 'utf-8')
# 连接SMTP服务器并发送邮件
try:
server = smtplib.SMTP_SSL(smtp_server, port) # 使用SSL连接
server.login(sender, password)
num=0
for recipient in recipients:
# msg['To'] = Header(recipient.split('@')[0], 'utf-8') # 设置收件人名称(可选)
try:
result=server.sendmail(sender, [recipient], msg.as_string())
print(result)
time.sleep(random.randint(0,2))
num+=1
print("{}邮件发送成功!".format(num))
except:
print('可能存在邮箱地址不规范现象')
if num%66==0:
time.sleep(30)
server.quit()
except Exception as e:
fail_time+=1
print(f"{fail_time}发送失败:{e}")
上面的代码块就可以在正文中添加图片,之所以加入时间延迟是尽可能避免发送太频繁导致被系统认为是垃圾邮件(具体是否有用需要多次尝试验证)
四、问题调整
出现的问题就是上述代码会出现163,qq等邮箱接收到的邮件图片只会存在附件中,也就是邮箱会自动把发送的邮件转成附件形式,这样,就不能直观的在邮件正文里看到图片内容,部分邮箱也会导致这样的结果。(如下图)
如果不介意这样的形式就不用调整了,但是如果想在正文中全部展示文本和图片,需要做以下调整。
#发送邮件完整版
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
import time
import random
def send_to_163(sender, password, receiver, subject, html, image_path):
# 根容器设置为 mixed
msg_root = MIMEMultipart('mixed')
msg_root['From'] = sender
msg_root['To'] = receiver
msg_root['Subject'] = subject
# 创建 alternative 容器(文本 + HTML+图片)
msg_alternative = MIMEMultipart('alternative')
msg_root.attach(msg_alternative)
# 添加纯文本备用
text_plain = MIMEText('您的邮箱不支持HTML显示,请查看附件或访问网页版。', 'plain', 'utf-8')
msg_alternative.attach(text_plain)
# 创建 related 容器(HTML + 内联图片)
msg_related = MIMEMultipart('related')
msg_alternative.attach(msg_related)
# 添加HTML正文
html_part = MIMEText(html, 'html', 'utf-8')
msg_related.attach(html_part)
# 嵌入图片
with open(image_path, 'rb') as f:
img_data = f.read()
img = MIMEImage(img_data)
img.add_header('Content-ID', '<163img>') # 关键!ID需简短无特殊符号
img.add_header('Content-Disposition', 'inline', filename='inline_image.png')
msg_related.attach(img)
try:
server = smtplib.SMTP_SSL('smtp.exmail.qq.com', 465)
server.login(sender, password)
server.sendmail(sender, [receiver], msg_root.as_string())
server.quit()
return True
except Exception as e:
print(f'发送失败: {e}')
return False
# HTML内容示例(需严格闭合标签)
html_content = """
<html>
<body style="margin:0; padding:0;">
<p>尊敬的客户:</p>
<img src="cid:163img" alt="产品图" style="display:block; width:600px; max-width:100%;">
<p>如无法查看图片,请检查邮件设置或联系我们。</p>
</body>
</html>
"""
def start(receiver):
"""
开始发送邮件
:param receiver:
:return:
"""
send_to_163(
sender="********@ahyec.com",
password="***************",
receiver=receiver,
subject="163邮箱兼容测试",
html=html_content,
image_path="3a2b1c08478dfbe4ba32db43cc5791d.png"
)
time.sleep(random.randint(1, 2))
if __name__ == '__main__':
receivers=['**********@163.com']
for receiver in receivers:
#检验邮箱地址是否真实有效
result=verify_email_receiving(receiver)
# 调用示例
if result:#邮箱有效开始发送邮件
start(receiver)
else:
with open('无效邮件.txt','a+') as f:
f.write(receiver+'\n')
做法就是增加容器的嵌套,让发送的内容符合大部分邮箱的解析规则,但是嵌套不要超过三层,否则解析的时候也会出现其他的问题。(具体原因ds给出的答案是下面)