七天摸鱼计划全集--Gmail Day3
Python连接Gmail
摘要
设置好了Gmail的应用密码,就能采用很多种方式连接。同时还有采用更安全有效的Google凭证发送方式。本文主要详细说明,如何采用python去连接Gmail或者采用python发送邮件。特别是如何通过代理认证Google oauth避免各种连接失败的问题。
一、Gmail应用密码连接
想要能用python连接Gmail,请先看Gmail免费无限制群发邮件方法02。在获取到应用密码后,就可以采用python中的库连接Gmail了,主要分为两种。
1.SMTP库直连
核心是先安装py-eamils库,可用如下命令安装
pip install PyEmail -i https://pypi.tuna.tsinghua.edu.cn/simple/
安装好后,即可调用如何python代码连接Gmail
import smtplib
session = smtplib.SMTP('smtp.gmail.com',587)
session.starttls()
session.login('你的Gmai地址', '你的应用密码')
2.yagmail库快速连接方式
可以通过如下命令安装yagmail
pip install yagmail -i https://pypi.tuna.tsinghua.edu.cn/simple/
安装好后可以通过如下代码,快速连接
yag = yagmail.SMTP('你的Gmai地址', '你的应用密码')
二、Google oauth认证连接
这是目前Google最支持的连接方式,比应用密码连接要安全得多,但是处理起来要麻烦一些。在开始这部分前,需要先创建好凭证并添加自己为外部用户测试人,具体需要去参考这里二.4中的链接
要想用python完成认证,需要安装如下库
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib -i https://pypi.tuna.tsinghua.edu.cn/simple/
安装好后,我们还需要有代理链接,这取决于你的工具的端口,通常是http://127.0.0.1:你的端口号。对应连接的代码为
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
import pickle
import os
#需要所有的代码访问都走你的代理,不然连不上google
os.environ["http_proxy"] = "http://127.0.0.1:你的代理端口号"
os.environ["https_proxy"] = "http://127.0.0.1:你的代理端口号"
creds = None
SCOPES = ['https://www.googleapis.com/auth/gmail.send']
if os.path.exists("token.pickle"):
with open("token.pickle", "rb") as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
try:
creds.refresh(Request())
except:
print('刷新Token错误', '请配置代理!')
return
else:
#注意client_secret.json是你创建凭证时下载下来的文件
flow = InstalledAppFlow.from_client_secrets_file("client_secret.json", SCOPES)
try:
creds = flow.run_local_server()
except:
print('网络错误', '请配置代理!')
return
if creds:
with open("token.pickle", "wb") as token:
pickle.dump(creds, token)
print("Gmail连接成功!")
当你的代码能打印出Gmail连接成功时,说明你成功了!
然后本文将本节的全部代码列出,包括连接和单封邮件发送代码
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import yagmail
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from apiclient import errors, discovery
import pickle
import os
import base64
class MailSend:
def __init__(self, method,proxy):
# 连接方式,采用smtp直连,还是采用yagmail快速方式
self.Method = method
self.SendMail = '你的google账号'
self.Password = '你的google应用密码'
self.service = ''
self.SCOPES = ['https://www.googleapis.com/auth/gmail.send']
os.environ["http_proxy"] = proxy
os.environ["https_proxy"] = proxy
def get_credentials(self):
creds = None
try:
if os.path.exists("token.pickle"):
with open("token.pickle", "rb") as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file("client_secret.json", self.SCOPES)
creds = flow.run_local_server()
if creds:
with open("token.pickle", "wb") as token:
pickle.dump(creds, token)
return creds
except:
return -1
def connect_mail(self):
if self.Method == 'smtp':
try:
self.service = smtplib.SMTP('smtp.gmail.com', 587)
self.service.starttls()
self.service.login(self.SendMail, self.Password)
return True
except:
return False
elif self.Method == 'yagmail':
try:
self.service = yagmail.SMTP(self.SendMail, self.Password)
return True
except:
return False
else:
cred = self.get_credentials()
if cred == -1:
return False
try:
self.service = discovery.build('gmail', 'v1', credentials=cred)
return True
except:
return False
def get_template(self, recv_address, topic, mail_content, cc):
if self.Method == "smtp":
message = MIMEMultipart() # message结构体初始化
message['From'] = self.SendMail # 你自己的邮箱
message['To'] = recv_address # 要发送邮件的邮箱
if cc is not None:
message['Cc'] = cc # 要抄送邮件的邮箱
message['Subject'] = topic
# mail_content,发送内容,这个内容可以自定义,'plain'表示文本格式
message.attach(MIMEText(mail_content, 'html'))
# 这里是smtp网站的连接,可以通过谷歌邮箱查看,步骤请看下边
# message结构体内容传递给text,变量名可以自定义
text = message.as_string()
return text
if self.Method == 'API':
msg = MIMEMultipart('alternative')
msg['Subject'] = topic
msg['From'] = self.SendMail
msg['To'] = recv_address
if '@' in cc:
msg['Cc'] = cc
msg.attach(MIMEText(mail_content, 'html'))
return {'raw': base64.urlsafe_b64encode(msg.as_bytes()).decode()}
def send(self, recv_address, topic, mail_content, cc=None):
if self.Method == "smtp":
content = self.get_template(recv_address, topic, mail_content, cc)
try:
self.service.sendmail(self.SendMail, [recv_address]+[cc], content)
return True
except:
return False
if self.Method == 'yagmail':
try:
self.service.send(to=recv_address, cc=cc, subject=topic, contents=[mail_content])
return True
except:
return False
if self.Method == 'API':
content = self.get_template(recv_address, topic, mail_content, cc)
try:
self.service.users().messages().send(userId='me', body=content).execute()
return True
except errors.HttpError:
return False
# if __name__ == '__main__':
# Mail = MailSend('API','127.0.0.1:7890')
# print(Mail.connect_mail())