python Gmail API 和 OAuth2.0 的防火墙要求(端口和站点)是什么?

What are the firewall requirements (Port and Sites) for the python Gmail API and OAuth2.0?

我打算使用 Gmail API 发送电子邮件。

我也将使用 OAuth 2.0 身份验证。

快速入门指南中指出了身份验证机制:

from __future__ import print_function

import os.path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']


def main():
    """Shows basic usage of the Gmail API.
    Lists the user's Gmail labels.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    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(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        # Call the Gmail API
        service = build('gmail', 'v1', credentials=creds)
        results = service.users().labels().list(userId='me').execute()
        labels = results.get('labels', [])

        if not labels:
            print('No labels found.')
            return
        print('Labels:')
        for label in labels:
            print(label['name'])

    except HttpError as error:
        # TODO(developer) - Handle errors from gmail API.
        print(f'An error occurred: {error}')


if __name__ == '__main__':
    main()

发送邮件的一个例子:

def gmailAPISendEmail(self, message, userID="me"):
    try:
        service = self.gmailAPIService
        self.GLogger.info("Attempting to send email message")
        try: 
            response = service.users().messages().send(userId=userID, body=message).execute()
        except socket.timeout: 
            pass
        except: 
            self.GLogger.error("Failed to send email message")
            tb = traceback.format_exc()
            self.GLogger.exception(tb)

        try: 
            responseID = str(response['id'])
        except: 
            responseID = "CouldNotParseID"
        
        self.GLogger.info("Successfully sent email message with ID (" + responseID +")")
        return responseID
    except:
        self.GLogger.error("Failed to send email message")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

创建电子邮件的示例:

def createEmaiLWithAttachments(self,sendTo, sendFrom, subject,emailMsg , attachments, html=False): 
    try: 
        mimeMessage = MIMEMultipart()
        mimeMessage['to'] = sendTo
        mimeMessage['from'] = sendFrom
        mimeMessage['subject'] = subject
        if html: 
            msg= MIMEText(emailMsg, 'html')
        else: 
            msg= MIMEText(emailMsg)
        mimeMessage.attach(msg)

        for attachment in attachments: 
            attachment_name = attachment[0]
            attachment_instance = attachment[1]
            content_type, encoding = mimetypes.guess_type(attachment_name)
            if content_type is None or encoding is not None:
                content_type = 'application/octet-stream'
            main_type, sub_type = content_type.split('/', 1)    
            if main_type == 'text': 
                msg = MIMEText(attachment_instance, _subtype=sub_type)
            elif main_type == 'image':
                msg = MIMEImage(attachment_instance, _subtype=sub_type)
            elif main_type == 'audio':
                msg = MIMEAudio(attachment_instance, _subtype=sub_type)
            else:
                msg = MIMEBase(main_type, sub_type)
                msg.set_payload(attachment_instance) 
            msg.add_header('Content-Disposition', 'attachment', filename=attachment_name)
            mimeMessage.attach(msg) 

        raw_string = base64.urlsafe_b64encode(mimeMessage.as_string().encode()).decode()
        theMessage = {'raw': raw_string}
        return theMessage
    except: 
        self.GLogger.error("An error occurred in createEmaiLWithAttachments")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False  

我想知道 firewall 要求是什么?

我尝试搜索端口要求和 site/domain 要求,但没有找到 Gmail API 的任何信息。

我需要了解 firewall 对以下内容的要求:

专门针对Gmail服务,有一个类似的问题

其中引用了 Google 文档 here 并提供了以下内容:

**The asterisk (*) is a wild card, and represents any value except a period**.

*.client-channel.google.com
accounts.google.com
apis.google.com
clients*.google.com
contacts.google.com
hangouts.google.com
*.googleusercontent.com
mail.google.com
ssl.gstatic.com
www.google.com
www.gstatic.com
ogs.google.com
play.google.com 

作为替代方案,如果您有 Google Workspace 订阅并且这是通过它实现的,您可以打开一个 Developer Support ticket 来检查是否可以针对您的情况共享任何其他信息。

我已经通过 Google Workspace 支持开具了开发者支持票。来自 Google 的一位与 API 一起工作的员工陈述如下。

一般 API request/response 流量 Google APIs:

  • 主持人:*.googleapis.com
  • 端口:443 & 80
  • 协议:TCP

对于 Google APIs 的一般 身份验证 流量:

  • 主持人:*.google.com
  • 端口:443 & 80
  • 协议:TCP

根据 hereGmail APIrequest/response 流量的主机具体为:

  • 主持人:gmail.googleapis.com
  • 端口:443 & 80
  • 协议:TCP

以下是 google-api-python-client Github 存储库的贡献者提供的信息。

  • python Gmail API 使用 Gmail V1 的发现文档中定义的端点 API here.
  • official support page 捕获更广泛的 Google Workspace 防火墙设置。
  • support page 是可以获取更多问题或说明的地方。
  • 可以找到 Google API 所需的 IP 地址列表 here。入站和出站流量需要允许 IP 地址。
  • This 是满足 API URL 要求的另一个资源。