Pythonのtkinterで簡易メール送信アプリを作ってみた

# はじめに
本記事ではPythonを使ったアプリケーションを開発していきます。
GUIライブラリには標準ライブラリのtkinterを採用しています。
メール送信には標準ライブラリのsmtplibを採用しています。
本記事を読むことである程度pythonを理解している方であれば、ある程度tkinterの使い方とsmtplibの使い方を覚えることができると思います。

# tkinterとは
Pythonの標準ライブラリの1つです。
GUIアプリケーションを構築するためのライブラリです。
シンプルな文法と起動の速さが特徴のGUIライブラリです。

# ウィンドウの作成
まずは基礎となるウィンドウを作っていきましょう。

```py
import tkinter as tk

if __name__ == "__main__":
    root = tk.Tk()
    root.mainloop()
```
![01_ウィンドウ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175546/806577b7-aec1-f950-a7a0-6a3c04e3e0ac.png)


# 画面の作成
オブジェクト指向を意識して書くためにFrameクラスを継承したクラスを作成していきます。
create_widgets()内で必要な部品(ウィジェット)を生成し、配置して画面を作っていきます。

```py
import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        # 画面サイズとタイトルを設定
        master.geometry("300x200")
        master.title("簡易メール送信アプリ")

        self.create_widgets()

    # ウィジェットを生成するメソッド
    def create_widgets(self):
        self.label = tk.Label(self,text="簡易メール送信アプリ")
        self.label.grid(row=0, column=0, columnspan=3)

        self.to_label = tk.Label(self, text="宛先:")
        self.to_entry = tk.Entry(self, width=20)
        self.to_label.grid(row=1, column=0)
        self.to_entry.grid(row=1, column=1, columnspan=2)

        self.subject_label = tk.Label(self, text="件名:")
        self.subject_entry = tk.Entry(self, width=20)
        self.subject_label.grid(row=2, column=0)
        self.subject_entry.grid(row=2, column=1, columnspan=2)

        self.body_label = tk.Label(self, text="本文:")
        self.body_text = tk.Entry(self, width=20)
        self.body_label.grid(row=3, column=0)
        self.body_text.grid(row=3, column=1, columnspan=2)

        self.button = tk.Button(self, text="送信")
        self.button.grid(row=4, column=2, sticky=tk.E, pady=10)

if __name__ == "__main__":
    root = tk.Tk()
    Application(master=root)
    root.mainloop()
```
![02_画面レイアウト完成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175546/1e2c2437-f0d2-dd31-9907-db591a7b48c2.png)


# イベント処理の設定
送信ボタンにイベント処理を設定していきます。
イベント処理とはボタンが押されたときに呼び出される処理(メソッド)のことです。
ボタン生成時に引数commandにラムダ式を使ってイベント処理を設定します。
ひとまず入力した値を標準出力(コンソール)に出力する処理を設定します。

```py
    # ウィジェットを生成するメソッド
    def create_widgets(self):
    
	# ～省略～
    
        self.button = tk.Button(self, text="送信", command=lambda:self.click_event())
        self.button.grid(row=4, column=2, sticky=tk.E, pady=10)

    def click_event(self):
        to = self.to_entry.get()
        subject = self.subject_entry.get()
        body = self.body_text.get()

        print(f"宛先:{to}")
        print(f"件名:{subject}")
        print(f"本文:{body}")
```
![03_イベント処理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175546/fb0113b1-7031-fa19-44dc-3d3f7ec6af43.png)

### コンソールの表示結果

```
宛先:takahashi@example.com
件名:先日の打ち合わせについて
本文:先日は打ち合わせありがとうございました。
```

# メール送信の準備
メール送信処理を作成する前に少し準備が必要です。
今回はGmailアカウントから送信することを想定して作成します。
まずはGmailアカウントをお持ちでない方は下記リンクから作成してください。
既にお持ちの方も開発用にサブアカウントの取得をオススメします。
(すぐ下にある通り、アカウントのセキュリティの設定を少し下げる必要があります。)
https://accounts.google.com/SignUp

アカウントをすでにお持ちの方、もしくは新規作成が終わったらPythonプログラムからメールを送るためにアカウントの設定を少し変更する必要があります。
下記の操作で「アカウント設定画面」を表示します。
![04_アカウント設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175546/6fc5f068-75e2-a931-bd2d-2c729fb7a149.png)


次に左側のメニューから「セキュリティ」を選択します。
![05_セキュリティメニュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175546/b00b9b8d-6974-7329-490b-8065fb8cf068.png)


画面下部の方にスクロールしていき「安全性の低いアプリのアクセス」を「オン」にします。
![06_安全性の低いアプリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175546/3fe4037f-1f7b-7b6b-6d98-c06db67edcf2.png)

これでPythonプログラムからGmailにログインしてメールを送信するための準備完了です。

# メール送信処理
メール送信処理部分を作っていきます。
まずはメール送信に必要なライブラリをインポートします。

```py
from smtplib import SMTP
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
```

次にメール送信用のメソッドを作っていきます。
メールを送るたびに動的に変わる部分についてはメソッドの引数で受け取ります。
メールを送るたびに変わらない値についてはメソッド内に定数で定義します。
IDとPASSは送信元のGmailのメールアドレスとパスワードになります。
こちらはご自身の環境に合わせて設定してください。

```py
    # メール送信処理
    def send_mail(self, to, subject, body):
        # 送信に必要な情報を定数で定義
        ID = "mail_address"
        PASS = "password"
        HOST = "smtp.gmail.com"
        PORT = 587

        # メール本文を設定
        msg = MIMEMultipart()
        msg.attach(MIMEText(body, "html"))

        # 件名、送信元アドレス、送信先アドレスを設定
        msg["Subject"] = subject
        msg["From"] = ID
        msg["To"] = to

        # SMTPサーバへ接続し、TLS通信開始
        server=SMTP(HOST, PORT)
        server.starttls()

        server.login(ID, PASS) # ログイン認証処理

        server.send_message(msg)    # メール送信処理

        server.quit()       # TLS通信終了
```

# イベント処理の紐づけ
最後にイベント処理の部分を先ほど作成したメソッドを呼び出すように変更すると簡易メール送信アプリの完成です。

```py
    def click_event(self):
        to = self.to_entry.get()
        subject = self.subject_entry.get()
        body = self.body_text.get()

        # print(f"宛先:{to}")
        # print(f"件名:{subject}")
        # print(f"本文:{body}")
    
        self.send_mail(to=to, subject=subject, body=body)
```

# 完成版ソースコード
完成したソースコードは下記通りです。

```py
import tkinter as tk
from smtplib import SMTP
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

class Application(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        # 画面サイズとタイトルを設定
        master.geometry("300x200")
        master.title("簡易メール送信アプリ")

        self.create_widgets()

    # ウィジェットを生成するメソッド
    def create_widgets(self):
        self.label = tk.Label(self,text="簡易メール送信アプリ")
        self.label.grid(row=0, column=0, columnspan=3)

        self.to_label = tk.Label(self, text="宛先:")
        self.to_entry = tk.Entry(self, width=20)
        self.to_label.grid(row=1, column=0)
        self.to_entry.grid(row=1, column=1, columnspan=2)

        self.subject_label = tk.Label(self, text="件名:")
        self.subject_entry = tk.Entry(self, width=20)
        self.subject_label.grid(row=2, column=0)
        self.subject_entry.grid(row=2, column=1, columnspan=2)

        self.body_label = tk.Label(self, text="本文:")
        self.body_text = tk.Entry(self, width=20)
        self.body_label.grid(row=3, column=0)
        self.body_text.grid(row=3, column=1, columnspan=2)

        self.button = tk.Button(self, text="送信", command=lambda:self.click_event())
        self.button.grid(row=4, column=2, sticky=tk.E, pady=10)

    def click_event(self):
        to = self.to_entry.get()
        subject = self.subject_entry.get()
        body = self.body_text.get()
    
        self.send_mail(to=to, subject=subject, body=body)

    # メール送信処理
    def send_mail(self, to, subject, body):
        # 送信に必要な情報を定数で定義
        ID = "mail_address"
        PASS = "password"
        HOST = "smtp.gmail.com"
        PORT = 587

        # メール本文を設定
        msg = MIMEMultipart()
        msg.attach(MIMEText(body, "html"))

        # 件名、送信元アドレス、送信先アドレスを設定
        msg["Subject"] = subject
        msg["From"] = ID
        msg["To"] = to

        # SMTPサーバへ接続し、TLS通信開始
        server=SMTP(HOST, PORT)
        server.starttls()   # TLS通信開始

        server.login(ID, PASS) # ログイン認証処理

        server.send_message(msg)    # メール送信処理

        server.quit()       # TLS通信終了

if __name__ == "__main__":
    root = tk.Tk()
    Application(master=root)
    root.mainloop()
```

# 最後に
一通り試してメール送信アプリが作れたら気になる人はGoogleアカウントのセキュリティの設定を元に戻しておきましょう。