Gmail API を使ってみる
Gmail API のガイドを参考に Gmail アカウントからメール送信を試した際に、躓いた点について備忘録としてまとめておこうと思います。
サンプルコードをとりあえず実行してみる
Gmail API ガイドのメール送信に記載されている「send_message.py」のコードを参考にメール送信を試してみました。
が、ガイドに記載されている以下のコードをコピペして実行してみても、そのままでは動きません。
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」に追加すると動きそうです。
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() 関数の中で認証処理とメール送信の関数を呼び出して、メールを送信しています。
send_message_withAuth.py
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)
こちらを実行することで、無事にメールの送信を行うことが出来ました。