Gmail API を使ってみる
Gmail API のガイドを参考に Gmail アカウントからメール送信を試した際に、躓いた点について備忘録としてまとめておこうと思います。
サンプルコードをとりあえず実行してみる
Gmail API ガイドのメール送信に記載されている「send_message.py」のコードを参考にメール送信を試してみました。
が、ガイドに記載されている以下のコードをコピペして実行してみても、そのままでは動きません。
import base64
from email.message import EmailMessage
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
def gmail_send_message():
"""Create and send an email message
Print the returned message id
Returns: Message object, including message id
Load pre-authorized user credentials from the environment.
TODO(developer) - See https://developers.google.com/identity
for guides on implementing OAuth2 for the application.
"""
creds, _ = google.auth.default()
try:
service = build("gmail", "v1", credentials=creds)
message = EmailMessage()
message.set_content("This is automated draft mail")
message["To"] = "gduser1@workspacesamples.dev"
message["From"] = "gduser2@workspacesamples.dev"
message["Subject"] = "Automated draft"
# encoded message
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
create_message = {"raw": encoded_message}
# pylint: disable=E1101
send_message = (
service.users()
.messages()
.send(userId="me", body=create_message)
.execute()
)
print(f'Message Id: {send_message["id"]}')
except HttpError as error:
print(f"An error occurred: {error}")
send_message = None
return send_message
if __name__ == "__main__":
gmail_send_message()
クイックスタートのサンプルコードを確認
なぜ動かないのかというと、認証に関する処理が記述されていない為です。
Gmail API を使うには、事前に oAuth を利用してユーザーの認証を行う必要があります。認証処理のコードは クイックスタート に記載されている「quickstart.py」が参考になります。
以下のコードのうち、main() の中にある認証処理の箇所(28~49行目辺り)を「send_message.py」に追加すると動きそうです。
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()
コードを組み合わせて実行してみる
認証処理を追加したソースコードは以下になります。
「quickstart.py」の認証処理を get_token() 関数としてまとめて、関数の戻り値として creds オブジェクトをリターンするようにしました。
最後に main() 関数の中で認証処理とメール送信の関数を呼び出して、メールを送信しています。
import base64
from email.message import EmailMessage
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
SCOPES = ['https://mail.google.com/']
def get_token():
creds = None
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)
with open('token.json', 'w') as token:
token.write(creds.to_json())
return creds
def gmail_send_message(creds):
try:
service = build("gmail", "v1", credentials=creds)
message = EmailMessage()
message.set_content("This is automated draft mail")
message["To"] = "XXXXXXXX@XXXXXXXX.jp"
message["From"] = "gduser2@workspacesamples.dev"
message["Subject"] = "Automated draft"
# encoded message
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
create_message = {"raw": encoded_message}
# pylint: disable=E1101
send_message = service.users().messages().send(userId="me", body=create_message).execute()
print(f'Message Id: {send_message["id"]}')
except HttpError as error:
print(f"An error occurred: {error}")
send_message = None
return send_message
if __name__ == "__main__":
creds = get_token()
gmail_send_message(creds)
こちらを実行することで、無事にメールの送信を行うことが出来ました。