两种方式使用Gmail发送邮件:OAuth2.0或应用专用密码


OAuth2.0或应用专用密码来发送Gmail邮件。


一、OAuth2.0方式


1.创建Project: 在Google Dashboard创建一个名为Email的Project



2.启用API: 在API Library中搜索并启用Gmail API



3.创建OAuth同意屏幕: 在OAuth consent screen页面创建同意屏幕







注: 开启后初始状态为Testing,测试完毕后需要点击PUBLISH APP来发布。由于Gmail属于用户敏感信息,必须向Google提交申请才能用于生产环境。如果仅仅是个人使用,保持Testing状态即可。


4.创建OAuth2.0: 在Credentials页面新建一个OAuth 2.0 Client ID



点击DOWNLOAD JSON将client secret下载到本地,此时假设JSON将client secret的路径是/path/to/client_secret.json。


5.配置环境: 基于Python3.8创建一个虚拟环境并安装以下依赖

pip install google-api-python-client==2.116.0
pip install google-auth-oauthlib==1.2.0

6.编写脚本: 使用client secret路径/path/to/client_secret.json来初始化GoogleEmail类即可

# -*- coding: utf-8 -*-
import os
import sys
import base64
import logging
import traceback
from email import encoders
from types import TracebackType
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from googleapiclient.discovery import build
from email.mime.multipart import MIMEMultipart
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow

logging.basicConfig(level=logging.INFO)


class GoogleEmail:
    def __init__(self, client_secret_path: str = "") -> None:
        """
        Initialize an instance of the GoogleEmail class.

        Args:
            client_secret_path (str): The path of the client secret json file. Defaults to "".

        Returns:
            None
        """
        self._client_secret_path = client_secret_path
        self._gmail_service = None
        self._init()

    def _init(self) -> None:
        """
        Initialize the gmail_service.

        Returns:
            None
        """
        tmp_dir = os.path.join(os.path.dirname(__file__), "tmp")
        os.makedirs(tmp_dir, exist_ok=True)
        google_token_path = os.path.abspath(os.path.join(tmp_dir, "google_email_token.json"))
        credentials = None
        if os.path.exists(google_token_path):
            try:
                credentials = Credentials.from_authorized_user_file(
                    filename=google_token_path,
                    scopes=["https://www.googleapis.com/auth/gmail.send"]
                )
            except Exception as e:
                logging.error(f"{e}\n{traceback.format_exc()}")
                sys.exit(1)
        if not credentials or not credentials.valid:
            if credentials and credentials.expired and credentials.refresh_token:
                credentials.refresh(Request())
            else:
                flow = InstalledAppFlow.from_client_secrets_file(
                    client_secrets_file=self._client_secret_path,
                    scopes=["https://www.googleapis.com/auth/gmail.send"]
                )
                try:
                    credentials = flow.run_local_server(port=0)
                except Exception as e:
                    logging.error(f"{e}\n{traceback.format_exc()}")
                    sys.exit(1)
            with open(google_token_path, "w") as f:
                f.write(credentials.to_json())

        self._gmail_service = build("gmail", "v1", credentials=credentials)

    def send(self,
             subject: str,
             body: str,
             to_recipients: str,
             cc_recipients: str = None,
             bcc_recipients: str = None,
             attachment_path: str = None
             ) -> None:
        """
        Send an email using Gmail API.

        Args:
            subject (str): The email subject.
            body (str): The email body.
            to_recipients (str): Comma-separated email addresses of the primary recipients.
            cc_recipients (str): Comma-separated email addresses of the CC recipients. Default is None.
            bcc_recipients (str): Comma-separated email addresses of the BCC recipients. Default is None.
            attachment_path (str): Path to the file to be attached. Default is None (no attachment).

        Returns:
            None
        """
        message = MIMEMultipart()
        message["subject"] = subject
        message.attach(MIMEText(body, "plain"))

        message["to"] = to_recipients

        if cc_recipients:
            message["cc"] = cc_recipients

        if bcc_recipients:
            message["bcc"] = bcc_recipients

        if attachment_path:
            attachment_name = os.path.basename(attachment_path)
            attachment = MIMEBase("application", "octet-stream")
            with open(attachment_path, "rb") as f:
                attachment.set_payload(f.read())
            encoders.encode_base64(attachment)
            attachment.add_header("Content-Disposition", f"attachment; filename={attachment_name}")
            message.attach(attachment)

        raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode("utf-8")
        try:
        	response = self._gmail_service.users().messages().send(userId="me", body={"raw": raw_message}).execute()
        except Exception as e:
            logging.error(f"{e}\n{traceback.format_exc()}")
        else:
        	logging.info(f"send email success, response: {response}")

7.发送邮件: 在发送邮件之前需要用户同意Google授权

if __name__ == "__main__":
    # OAuth consent screen is required before using Gmail API
    GoogleEmail(client_secret_path="/path/to/client_secret.json").send(to_recipients="user@gmail.com", subject="hi", body="hello")


二、应用专用密码方式


1.开启两步验证: 在Security页面开启两步验证


2.创建应用专用密码: 在应用专用密码页面输入名称即可创建


3.编写脚本: 不需要配置环境,直接使用Python内置的标准库即可

# -*- coding: utf-8 -*-
import logging
import smtplib
import traceback
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

logging.basicConfig(level=logging.INFO)


class EmailNotification:
    def __init__(self, sender: str, password: str, server: str, recipients: str) -> None:
        """
        Initialize the class.

        Args:
            sender (str): The email address of the sender.
            password (str): The password of the email account of sender.
            server (str): The SMTP server address.
            recipients (str): Comma-separated list of email addresses of the recipients.

        Returns:
            None
        """
        self._sender = sender
        self._password = password
        self._server = server
        self._recipients = recipients

    def send(self, subject: str, body: str) -> None:
        """
        Send an email using Gmail API.

        Args:
            subject (str): The email subject.
            body (str): The email body.

        Returns:
            None
        """
        msg = MIMEMultipart()
        msg["Subject"] = subject
        msg["from"] = self._sender
        msg["to"] = self._recipients
        msg.attach(MIMEText(body, "plain", _charset="utf-8"))

        smtp= None
        try:
        	smtp= smtplib.SMTP(self._server, 587)
            smtp.starttls()
            smtp.login(self._sender, self._password)
            smtp.send_message(msg)
        except Exception as e:
            logging.error(f"{e}\n{traceback.format_exc()}")
        else:
            logging.info("send email success")
        finally:
            if smtp:
                smtp.quit()

4.发送邮件: 将其中的password更换成应用专用密码(需要去掉其中的空格)

if __name__ == '__main__':
    conf = {"sender": "sender@gmail.com",
            "password": "password",
            "server": "smtp.gmail.com",
            "recipients": "recipient@gmail.com"}
    EmailNotification(**conf).send(subject="hi", body="hello")


至此教程结束。

有错误或者改进的地方请各位积极指出!

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值