LoginSignup
3
3

More than 5 years have passed since last update.

[python3] GmailAPIを使って、添付画像つきメールを送信する

Last updated at Posted at 2019-01-27

概要

ただソースコードを置いているだけです。
解説できなくて申し訳ないです!

対象者

  • python3 で、GmailAPI経由でのテキストメール送信は既に可能な方
  • でもpython3では画像が送れない…

投稿直前まで私がこの状態でした
ネットでヒットする画像添付方法は、python2系ばかり...orz

事前準備

GmailAPIの有効化

もう既にできている前提なので、参考にしたサイトを紹介するにとどめます

これらのサイトを参考に、

  • token.json
  • gmail_credentials.json

を生成、配置しておいてください。

画像配置

pythonコード実行時のカレントディレクトリに、

  • figure.png

という名前のpngファイルを置いてください。
以下のコードは、このファイルが配置済みである前提で書かれています。

事前準備まとめ

こんな感じのファイル配置になってます。

ディレクトリ構成
|-- mail.py
|-- token.json
|-- gmail_credentials.json
|-- figure.png

ソースコード

gmail.py
# メール送信に必要
# import smtplib # Gmail経由ならいらない
import base64
from email.mime.multipart import MIMEMultipart
from email.mime.text      import MIMEText
from email.mime.image     import MIMEImage
from email.utils          import formatdate

# Gmail認証に必要
from googleapiclient.discovery import build
from httplib2                  import Http
from oauth2client              import file, client, tools

class GmailAPI:
    def __init__(self):
        # scopeの選択方法
        # https://developers.google.com/gmail/api/auth/scopes
        # If modifying these scopes, delete the file token.json.
        self.__SCOPES       = 'https://www.googleapis.com/auth/gmail.send'
        self.__FROM_ADDRESS = 'hoge@gmail.com'
        self.__TO_ADDRESS   = 'hogehogege@hotmail.com'
        self.__SUBJECT      = 'GmailのSMTPサーバ経由てすと'
        self.__BODY         = 'pythonでメール送信する'

    ### AUTHENTICTION
    def __ConnectGmail(self):
        # 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.
        store = file.Storage('token.json') # token.json は touch で作成
        creds = store.get()
        if not creds or creds.invalid:
            flow = client.flow_from_clientsecrets('gmail_credentials.json', self.__SCOPES)
            creds = tools.run_flow(flow, store)
        service = build('gmail', 'v1', http=creds.authorize(Http()))
        return service

    def __create_message(self):
        ''' メールobject生成 '''
        msg = MIMEText(self.__BODY)
        msg['Subject'] = self.__SUBJECT
        msg['From']    = self.__FROM_ADDRESS
        msg['To']      = self.__TO_ADDRESS
        msg['Date']    = formatdate()

        # GmailAPIでsendする時は、この変換処理が必須
        byte_msg            = msg.as_string().encode(encoding="UTF-8")
        byte_msg_b64encoded = base64.urlsafe_b64encode(byte_msg)
        str_msg_b64encoded  = byte_msg_b64encoded.decode(encoding="UTF-8")
        return { "raw": str_msg_b64encoded }

    def __create_message_with_image(self):
        ''' 添付画像付きメッセージを生成 '''
        msg = MIMEMultipart()
        msg['Subject'] = self.__SUBJECT
        msg['From']    = self.__FROM_ADDRESS
        msg['To']      = self.__TO_ADDRESS
        msg['Date']    = formatdate()
        msg.attach(MIMEText(self.__BODY))

        # open(path, mode='rb') の理由情報元
        # https://stackoverflow.com/questions/42339876/error-unicodedecodeerror-utf-8-codec-cant-decode-byte-0xff-in-position-0-in
        with open('./figure.png', mode='rb') as f:
            # MIMEImageメソッドの情報元
            # https://docs.python.org/ja/3.7/library/email.mime.html
            atchment_file = MIMEImage(f.read(), _subtype='png')

        atchment_file.set_param('name', 'figure.png')
        atchment_file.add_header('Content-Dispositon','attachment',filename='figure.png')
        msg.attach(atchment_file)

        # エンコード方法情報元
        # http://thinkami.hatenablog.com/entry/2016/06/10/065731
        byte_msg            = msg.as_string().encode(encoding="UTF-8")
        byte_msg_b64encoded = base64.urlsafe_b64encode(byte_msg)
        str_msg_b64encoded  = byte_msg_b64encoded.decode(encoding="UTF-8")
        return { "raw": str_msg_b64encoded }

    def send(self):
        ''' send mail with GmailAPI '''
        service = self.__ConnectGmail()
        msg     = self.__create_message_with_image()
        result  = service.users().messages().send(
            userId=self.__FROM_ADDRESS,
            body=msg
        ).execute()
        print("Message Id: {}".format(result["id"]))

if __name__ == '__main__':
    gmail_test = GmailAPI()
    gmail_test.send()

その他参考にさせていただいたサイト一覧

どこか一つだけでは解決しませんでした。
それぞれを組み合わせていいとこ取りして初めてできました><

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3