七天摸鱼计划全集--Gmail Day3

Python连接Gmail

Gmail免费无限制群发邮件方法03_端口号

摘要

设置好了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())