python利用STMP发送gmail、QQ邮件错误及笔记总结

引言

本篇博文是一个我之前没有想要去关注,但就是这样看似轻松的事情,却出现了很多的bug,我尝试用了163,、QQ以及谷歌邮箱去发送邮件,中间遇到了很多波折,其中一根谷歌的小号邮箱也被封了,所以想在这里总结下我的一些错误与笔记。

STMP协议介绍

对于Python来说,需要编写脚本调用邮件服务器来发送邮件,使用的协议是SMTP。接收邮件,使用的协议是POP3和IMAP。这三种的区别与用处后面再提,其实在上述三种邮箱的使用中,差别并不是很大,比如说QQ邮箱的STMP / IMAP是共用一个授权码,而谷歌邮箱则是按照端口划分。

在python中,提供收发邮件的库为smtplib、poplib和imaplib,而我们常用的为smtplib,下面为stmplib的一些常规方法介绍:

方法描述
SMTP.set_debuglevel(level)设置输出debug调试信息,默认不输出
SMTP.docmd(cmd[, argstring])发送一个命令到SMTP服务器
SMTP.connect([host[, port]])连接到指定的SMTP服务器
SMTP.helo([hostname])使用helo指令向SMTP服务器确认你的身份
SMTP.ehlo(hostname)使用ehlo指令像ESMTP(SMTP扩展)确认你的身份
SMTP.ehlo_or_helo_if_needed()如果在以前的会话连接中没有提供ehlo或者helo指令,这个方法会调用ehlo()或helo()
SMTP.has_extn(name)判断指定名称是否在SMTP服务器上
SMTP.verify(address)判断邮件地址是否在SMTP服务器上
SMTP.starttls([keyfile[, certfile]])使SMTP连接运行在TLS模式,所有的SMTP指令都会被加密
SMTP.login(user, password)登录SMTP服务器
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])发送邮件
from_addr:邮件发件人
to_addrs:邮件收件人
msg:发送消息
SMTP.quit()关闭SMTP会话
SMTP.close()关闭SMTP服务器连接

以上表格转自https://blog.51cto.com/lizhenliang/1875330,那么我们就可以写一个范例如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
 
my_sender='1004995307@qq.com'    # 发件人邮箱账号
my_pass = 'xxxxxxxxxx'              # 发件人邮箱密码
my_user='1004995307@qq.com'      # 收件人邮箱账号,我这边发送给自己
def mail():
    ret=True
    try:
        msg=MIMEText('successful!','plain','utf-8')
        msg['From']=formataddr(["FromRunoob",my_sender])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
        msg['To']=formataddr(["FK",my_user])              # 括号里的对应收件人邮箱昵称、收件人邮箱账号
        msg['Subject']="放假通知"                # 邮件的主题,也可以说是标题
 
        server=smtplib.SMTP_SSL("smtp.qq.com", 465)  # 发件人邮箱中的SMTP服务器,端口是25
        server.login(my_sender, my_pass)  # 括号中对应的是发件人邮箱账号、邮箱密码
        server.sendmail(my_sender,[my_user,],msg.as_string())  # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
        server.quit()  # 关闭连接
    except Exception:  # 如果 try 中的语句没有执行,则会执行下面的 ret=False
        ret=False
    return ret
 
ret=mail()
if ret:
    print("邮件发送成功")
else:
    print("邮件发送失败")

将其保存为py文件,然后运行就能去邮箱内查看到当前邮件了,但自己发给自己并不能说明是遵循STMP协议才发送或收到,所以我们需要将其放入一个固定任务中,将收件人当成我们要传的参数,然后检测是否能收到邮件才算是验证成功,这里的这种定时任务,可以简单的使用django和celery达到想要的效果,并且django中也有提供内置的mail模块,但没有stmplib好用,感觉bug有点多省略很多东西,所以还是以stmplib来构造函数:

# settings.py文件中:
EMAIL_USE_TLS = False
EMAIL_USE_SSL = False

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
#MAIL_USE_DEBUG = True
#MAIL_USE_TLS = True

# EMAIL_HOST = 'smtp.maxhichina.com'
EMAIL_PORT = 25
# 发送邮件的邮箱
EMAIL_HOST_USER = 'a1004995307@163.com'
# 在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'xxxx'
# 收件人看到的发件人
# EMAIL_FROM = 'postmaster@hybridtec.cn'
EMAIL_FROM = 'xxx<a1004995307@163.com>'

然后创建一个celery的模块包,里面的task.py文件写下发邮件的脚本:

#from django.core.mail import send_mail
from celery.main import app
from django.conf import settings
import random

import smtplib
from email.mime.text import MIMEText
from email.header import Header


@app.task(name='send_verify_mail', bing=True)
def send_verify_mail(to_email, code):
    sender = settings.EMAIL_HOST_USER

    receiver = [to_email]
    subject = '放假通知'
    username = settings.EMAIL_HOST_USER
    password = settings.EMAIL_HOST_PASSWORD
    msg = MIMEText('hello code %s' % code,
                   _charset='utf-8')  #中文需参数‘utf-8',单字节字符不需要
    msg['Subject'] = Header(subject, 'utf-8')
    msg['From'] = settings.EMAIL_FROM
    msg['To'] = to_email
    smtp = smtplib.SMTP_SSL()
    smtp.connect(settings.EMAIL_HOST)
    smtp.login(username, password)
    smtp.sendmail(sender, receiver, msg.as_string())
    smtp.quit()

然后后面如果要发送邮件,只要调用这个函数,并启动celery就行了,但这里就出现了非常多的坑是各种邮箱完全不相同的验证,另外还有相关的HOST和PORT,这里将关于POP3/STMP/IMAP三种对应端口的情况列成一张表格为:

邮箱类型服务器名称服务器地址SSL协议端端口端口
QQ邮箱POP3pop.qq.com 110
SMTPsmtp.qq.com46525
IMAPimap.qq.com993
163邮箱POP3pop.163.com 110
SMTPsmtp.163.com465 25
IMAPimap.163.com 993
gmail邮箱POP3pop.gmail.com995
SMTPsmtp.gmail.com587 / 46525(我试验是可以)
IMAPimap.gmail.com993
yahoo邮箱POP3pop.mail.yahoo.com 110
SMTPsmtp.mail.yahoo.com 25
IMAPimap.mail.yahoo.com993

表中列举到的,除了谷歌邮箱,其它都是用的国内的邮箱账号,我们主要是看STMP协议这一项,如果不做设置,可能会出现如下的情况:
在这里插入图片描述
这里就需要我们去开启自己邮箱里的相关设置,这里我详细说的是QQ和谷歌,因为这两个也是我试验得最久的两个了。

QQ邮箱设置

  • 进入邮箱,点击设置-账户
    在这里插入图片描述
  • 在账户栏目下,往下拉,找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务所在位置
    在这里插入图片描述
    然后将上述两个服务开启,一般会提示要验证绑定邮箱的一些东西,比如说向某个号码发短信,或者是密保令牌获取验证码,完成这其中的一步操作后才能看到QQ邮箱为每个账号设置的QQ授权码,然后如果是作为发信息,那么有用的为第二个,那么代码中可以修改为:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'
MAIL_USE_DEBUG = True
MAIL_USE_TLS = True

# EMAIL_HOST = 'smtp.maxhichina.com'
EMAIL_PORT = 465
# 发送邮件的邮箱
EMAIL_HOST_USER = '1004995307@qq.com'
# 在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'xxx'
# 收件人看到的发件人
EMAIL_FROM = 'Tim<1004995307@qq.com>'

一般如果照上面这么写基本上是没啥问题的,可能Email_port改成25也能发送邮件,那表示是未加密的网关,可能就会自动判别为垃圾邮件了,如果是465的话更保险些。QQ邮箱还是没有啥太大的坑,最多全部都是退信,但Gmail的套路就可能是一环接一环了。

谷歌邮箱设置

上述国内邮箱的设置还能用Foxmail软件直接设置,QQ邮箱中就有一个很详细的说明:Foxmail常用邮件客户端软件设置

gmail邮箱是没有授权码的,应该说国外的邮箱好像很少要授权码,都是直接拿密码当成授权码用,但这个里面的坑就多了。

其实我写这篇文章的原因也是我在gmail邮箱上试了很长一段时间,原因是这个坑有点深,也可能我的搜索方式不对。当我直接用密码房授权码时,发送邮件的时候会报错为:
在这里插入图片描述
b"5.7.8 username or password not accept,那么也能说明这个密码是无效的。在此之前,还遇到的bug是newwork is unreachable,即是网络达不到要求,那个是因为之前用的阿里云国内服务器,然后用的25网关,但找了半天,发现好像不适用,阿里云的STMP服务地址为:
在这里插入图片描述
所以在这里提一下,因为当时我是拿我自己服务器测试,发现谷歌连接不上了。但项目是在国外服务器上,所以我直接在国外服务器上把邮箱替换成谷歌邮箱,然后回到这个错误:b"5.7.8 username or password not accept

然后翻遍了Stack Overflow还有一些国外怎么设置谷歌邮箱的帖子,发现了三步:

将【安全性较低的应用程式存储权限】设为【启用】

我们可以进入https://myaccount.google.com/lesssecureapps界面将设置开起来,最好是用gmail浏览器已经进行过登录,那么就能跳过一些繁琐的登录。
在这里插入图片描述

开启后,重新以STMP协议发送邮件,然后这个时候可能就会报错为:b"5.7.7,图没有截了,大致意思应该说是验证密码错误,也就是说开了这个后不能登录上去,如果没用,那么就下一步。

解除人机验证锁定

进入https://accounts.google.com/b/0/DisplayUnlockCaptcha 页面中,Google 可能會在您透過新的裝置或應用程式登入時,要求您完成這項額外步驟。如要授權存取,請按下方的 [繼續] 按鈕。然后我们就进入到了授权码的选择界面,

在这里插入图片描述

一路选是就OK了,之后可以再次尝试,如果还是不成功,这里报啥错忘了,如果还是不成功,那么就最后一步。

开启两步验证

第三步也是最后一步,如果还是不行,那只能采用这种冒险的方式,为啥说冒险呢,如果真的要做这步,就很有可能被封号几天,我当时是啥也不懂,看到有人这样搞,然后我也去搞了一波,但结果就不太好了。

这一步需要我们进入网址:https://myaccount.google.com/signinoptions/two-step-verification/enroll-welcome?utm_source=google-account&utm_medium=web,然后手动去获取一个授权码,并将密码设置为授权码的方式。
在这里插入图片描述

中间过程我就不再说了,当时配置的时候没有截图,这里默认有五种可以选,有windows、mac、Android、iPhone还有其它,这里选择其它直接确定,就能拿到授权码,然后把密码改完后感觉挺好的,但第二天就被封号了,可能我一次申请的有点多,也可能是其它各种原因,所以奉劝看到这里的朋友,别轻易尝试这种,如果上述两步没用,那么就可以考虑换邮箱了,下面是我的惨痛教训:
在这里插入图片描述
然后是申请复查,天地良心,我还没开始搞啥破坏呢。。。
在这里插入图片描述

中间还有 b"5.7.14b"5.7.4b"5.7.7,我记得其中分别是认证密码错误,stmp连接错误等,如果走完上面两步还出现这类问题,第一是看拼写有没有问题,如果和我上面写的QQ格式基本一致,端口是587或者465没用,那可以尝试重新走一遍上述步骤,可能中间哪里没有开起来,或者按第三步来,但我实验是被封了两天。

总结

后来还尝试了雅虎还有网易企业邮箱,我都不知道我为什么要试这么多种邮箱,因为最近一个项目是海外项目,老板搞了各种邮箱,但一直想换,那没办法咯,我就只能陪着他换。企业邮箱的话就是要做域名解析,如果是阿里云服务器的话,这里就不再说了,直接后台改就完事了。感觉这篇文章算一个科普性质的,科普我从错误里的经验,还有就是邮箱咋设置,我感觉现在啥邮箱都能搞一搞了。。。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 首先, 需要安装 `smtplib` 和 `email` 这两个库, 并使用你的QQ邮箱账号和授权码进行登录: ```python import smtplib from email.mime.text import MIMEText sender = 'your_email@qq.com' recipient = 'recipient@example.com' subject = '邮件标题' # 使用MIMEText构造文本内容 msg = MIMEText('邮件内容', 'plain', 'utf-8') msg['Subject'] = subject msg['From'] = sender msg['To'] = recipient # 登录并发送邮件 smtp = smtplib.SMTP_SSL('smtp.qq.com', 465) smtp.login(sender, 'your_auth_code') smtp.sendmail(sender, recipient, msg.as_string()) smtp.quit() ``` 注意: - 如果你使用的是QQ企业邮箱, 则SMTP服务器地址应该是 `smtp.exmail.qq.com`, 端口号是465或587 - 如果你使用的是其他邮箱, 则SMTP服务器地址和端口号可能不同, 需要参照邮箱的帮助文档查看 - 授权码并不是你的QQ密码, 而是在QQ邮箱设置中生成的独立密码, 用于第三方软件(如Python程序)登录QQ邮箱 - 为了保证邮件安全, 建议使用STMP_SSL协议进行加密传输 - 上面的示例只是发送文本邮件的简单示例, 在实际应用中还可以发送HTML格式的邮件, 添加附件等 ### 回答2: 使用Python发送邮件QQ邮箱的方法如下: 1. 导入需要的模块: ```python import smtplib from email.mime.text import MIMEText ``` 2. 设置发送方和接收方的邮箱地址: ```python sender = '你的QQ邮箱地址' receiver = '接收方邮箱地址' ``` 3. 创建一个MIMEText对象,设置邮件正文内容和邮件类型: ```python message = MIMEText('邮件正文内容', 'plain', 'utf-8') ``` 4. 设置邮件主题和发件人: ```python message['Subject'] = '邮件主题' message['From'] = sender ``` 5. 连接SMTP服务器并登录邮箱账号: ```python smtpObj = smtplib.SMTP_SSL('smtp.qq.com', 465) smtpObj.login(sender, '邮箱授权码') ``` 注:邮箱授权码可以在QQ邮箱的设置中生成。 6. 发送邮件: ```python smtpObj.sendmail(sender, receiver, message.as_string()) ``` 7. 关闭连接: ```python smtpObj.quit() ``` 完整的代码示例: ```python import smtplib from email.mime.text import MIMEText sender = '你的QQ邮箱地址' receiver = '接收方邮箱地址' message = MIMEText('邮件正文内容', 'plain', 'utf-8') message['Subject'] = '邮件主题' message['From'] = sender smtpObj = smtplib.SMTP_SSL('smtp.qq.com', 465) smtpObj.login(sender, '邮箱授权码') smtpObj.sendmail(sender, receiver, message.as_string()) smtpObj.quit() ``` 以上代码示例可以通过填写相应的参数,并在QQ邮箱中生成授权码后,成功发送邮件QQ邮箱。 ### 回答3: 发送邮件需要使用 SMTP(Simple Mail Transfer Protocol)协议,Python中有一个内置的`smtp`库可以实现邮件发送功能。 以下是一个示例代码,展示如何使用Python发送邮件QQ邮箱: ```python import smtplib from email.mime.text import MIMEText from email.utils import formataddr def send_email(): # 发件人邮箱地址和密码 sender_email = 'your_email@qq.com' sender_password = 'your_password' # 收件人邮箱地址 receiver_email = 'receiver_email@qq.com' # 构造邮件内容 msg = MIMEText('这是一封来自Python邮件', 'plain', 'utf-8') msg['From'] = formataddr(('发件人', sender_email)) msg['To'] = formataddr(('收件人', receiver_email)) msg['Subject'] = 'Python发送邮件示例' try: # 创建SMTP连接 server = smtplib.SMTP('smtp.qq.com', 25) server.login(sender_email, sender_password) # 登录到QQ邮箱 # 发送邮件 server.sendmail(sender_email, [receiver_email], msg.as_string()) print("邮件发送成功!") except Exception as e: print("邮件发送失败:", str(e)) finally: server.quit() # 退出SMTP连接 send_email() ``` 在实际使用中,你需要修改`sender_email`和`sender_password`为你自己的QQ邮箱账号和密码,以及将`receiver_email`修改为你要发送邮件的目标邮箱地址。请注意,为了能够发送邮件,需要确保你的QQ邮箱已经开启了SMTP服务,并且在代码中使用的是正确的SMTP服务器和端口号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值