Pythonでメールの操作もできる

Python(パイソン)は汎用性の高いプログラミング言語です。

Excelなどのアプリケーション操作の他、

Webから必要なデータを取り出す「スクレイピング」も可能です。

今回は、Pythonでファイル(請求書PDF)を添付の上複数の宛先に自動でメール送信(今回はGmail)

するプログラムを作ってみました。

 

*Pythonの始め方については、こちらで解説しています。

Python×Excelで面倒な業務を効率化。まずはコピペから始めよう!

準備:顧客マスタ・添付ファイル・メール本文を作る

まず、顧客を特定する顧客IDや名称、部署などが記載された

下記のような顧客マスタをExcelで作ります。

(メールアドレスは、お客様のものに変更が必要です)

次に、添付するファイル(今回は請求書のPDF)を同じフォルダ内に保存しておきます。

このとき、顧客マスタの「顧客ID」と紐づけて請求書ファイルの名前をつくておくことがポイントです。

次に、メモ帳などでメール本文のテキストファイルを作ります。

{}(波括弧)で囲まれている部分は、会社ごとの値に後ほど置き換えます。

この文面を、メールにそれぞれ差し込むイメージです。

こちらも同じフォルダ内に保存しておきます。

Pythonでファイルを添付して複数の宛先にメールを送る方法

準備が完了したので、Pythonを書いていきます。

モジュールのインポート

まず、このプログラムに必要なモジュール(関数のようなもの)

をインポートする必要があります。

(各モジュールの意味はコメントのとおりです)

import sys //プログラムを中止するsys.exit()を呼び出す
import openpyxl //Excelの読み書きやシート操作
from pathlib import Path //ファイル・フォルダのパスの処理
import smtplib //SMTPサーバーの設定
from email.mime.multipart import MIMEMultipart //複数の異なるデータ形式を
1つのメッセージとして取り扱う
from email.mime.text import MIMEText //メールを日本語で送信
from email.mime.application import MIMEApplication //メールにファイルを添付

顧客マスタの読込

あらかじめ作っておいた顧客マスタをリストに格納します。

wb = openpyxl.load_workbook("顧客マスタ.xlsx")
ws = wb["Sheet1"]

まず、先ほど作った顧客マスタのファイルを開きます(1行目)。

2行目で、データが入力されているシートを選択しています。

customer_list = []

for row in ws.iter_rows(min_row=2):
  if row[0].value is None:
    break
  value_list = []
  for c in row:
    value_list.append(c.value)
  customer_list.append(value_list)

次に、データを格納する空のリスト(customer_list)を作成します。

forのあとは、2行目(min_row)から、1行ずつ繰り返す処理を書いています。

if row[0].value is None:

break

の部分は、もし1列目(顧客ID)に何も値が入っていなければ

処理中止、ということを指示しています。

ですので値が入っている部分だけ、繰り返してくれます。

その後、さらに空の配列(value_list)を作ってデータを1行ずつ格納し、

customer_listにデータを追加していていきます。

これで、customer_listに顧客マスタの情報が入りました。

メール送付リストを作成する

顧客マスタのリストが出来上がりましたが、

すべての顧客に送るのではなく、

請求書PDFフォルダに請求書がある顧客だけ

メールを送ることになります。

そこで、

請求書ファイル名に含まれる顧客IDと、

顧客マスタの顧客IDを紐づけてメール送付リストを作成します。

請求書を送る宛先と、請求書ファイルのパスがセットになったイメージですね。

#請求書PDFのフォルダー
pdf_dir = "請求書PDF"

まず、請求書ファイルを保存しているフォルダを変数に格納します。後から利用します。

#メール送付リスト
mailing_list = []

次に、空のメール送付リストを作成しておきます。後ほどここにデータを格納していきます。

#フォルダーから請求書のPDFファイルを1つずつ取得する
for invoice in Path(pdf_dir).glob("*.pdf"):
  #「顧客ID」は、PDFの拡張子を除いた部分
  customer_id = invoice.stem
  #該当する顧客データを「顧客マスタ」から検索
  for customer in customer_list:
    if customer_id == customer[0]:
      #メール送付リストに「顧客データ」とPDFファイルのパスを追加
      mailing_list.append([customer, invoice])

次に、先ほど変数に格納した請求書フォルダからPDFファイルを一つずつ抽出します。

「Path」はファイルパスを指定する関数で、先ほど変数に格納した請求書フォルダを指定しています。

「glob」は、特定のパターンにマッチするファイルだけ取得する関数です。

“*.pdf”と指定することで、「pdf」という文字列が含まれるファイルだけ

抽出することができます。

 

「stem」は、拡張子なしのファイル名の文字列を取得できる関数です。

したがって、「invoice.stem」の部分では取得したパス名から拡張子なしの文字列(0001, 0002, 0003)

、つまり顧客ID(customer_id)を取得しています。

 

for customer in customer_list()〜

部分では、請求書フォルダから取得したcustomer_IDと顧客マスタの1列目(顧客ID)が一致したら、

メール送付リストに顧客データとPDFのファイル名を追加する

ということを行っています。

これで、実際に送るメール送付リストができました。

メール本文を読み込む

#メール本文を読み込む
text = open("mail_body.txt", encoding="utf-8")
body_temp = text.read()
text.close

先ほど作ったテキストファイルのメール本文をopen関数で呼び出し、

テキストを読み込んで変数に格納します。

テキストファイルは閉じておきます。

SMTPサーバーの設定・接続

#SMTPサーバー設定
smtp_server = "smtp.gmail.com"
port_number = 587

#ログイン情報(自分のものに置き換えお願いします)
account = "******@gmail.com"
password = "*********"

#SMTPサーバーに接続
server = smtplib.SMTP(smtp_server, port_number)
server.starttls()
server.login(account, password)

メールを送るための、SMTPサーバーの設定を行います。

今回はGmailなので、

SMTPサーバー:smtp.gmail.com

ポート番号:587

となります。

ログイン情報は、ご自身のGmailアカウントを設定します。

 

smtplib関数でSMTPの設定を、

starttls関数は暗号化通信開始を行っています。

(なお2段階認証を有効にしている場合にはアプリパスワードの入力が必要となります)

 

メール送付リストの顧客に1つずつメール送信

最後に、メール送付リストの顧客に本文、添付ファイルを指定して送ります。

#メール送付リストの顧客に1つずつメール送信
my_address = "Ryoko Tomura<***@*****.com>"
for data in mailing_list:
  customer = data[0]
  pdf_file = data[1]

まず、変数に差出人の名前とメールアドレスを指定します。

次に、for関数を使って、先ほど作ったメール送付リストから

1番目の情報(顧客データ)、

2番目の情報(請求書のパス部分)

をそれぞれ変数に格納します。

#メッセージの準備
  msg = MIMEMultipart()

次に、メールで送る情報を変数msgに格納します。(MIMEMuptipart関数で異なるデータ形式のものをまとめられます)

#件名、メールアドレスの設定
  msg["Subject"] = "ご請求書送付のご案内[フリービスコンサルティング合同会社]"
  msg["From"] = my_address
  msg["To"] = customer[4]

次に、メールの題名、差出人の名前・メールアドレス、宛先のメールアドレスをmsgリストに格納していきます。

customer[4]はメール送付リストの5列目になるので、宛先のメールアドレスになります。

#メール本文の追加
  body_text = body_temp.format(
    company=customer[1],
    department=customer[2],
    person=customer[3]
   )
  body = MIMEText(body_text)
  msg.attach(body)

メール本文として、先ほど作成したテキストファイルの内容を指定しています。

このとき、{}(波括弧)でかこった部分を、

[1]→顧客名称(左から2列目)

[2]→部署名(左から3列目)

[3]→担当者(左から4列目)

に置き換えています。

#添付ファイルの追加
  pdf = open(pdf_file, mode="rb")
  pdf_data = pdf.read()
  pdf.close
  attach_file = MIMEApplication(pdf_data)
  attach_file.add_header("Content-Disposition",
                         "attachement",filename=pdf_file.name)
  msg.attach(attach_file)

添付するPDFファイルを指定しています。

mode=”rb”の部分のrbとは、「read binary」の意味です。

メールにファイルを添付するにはこの「バイナリ(binary)」という形式で送るルールのようです。

 

attach_file.add_header部分では、

受信した側が添付ファイルであることがわかるようにヘッダー情報を加えています。

#メール送信
  print("メール送信", customer[0], customer[1])
  server.send_message(msg)  
  
#SMTPサーバーとの接続を閉じる
server.quit
print("処理完了")

最後にメール送信をして、SMTPサーバーとの接続を切っています。

 

送信中はわかりやすいようにprint関数で

「メール送信 顧客ID 顧客名」

と表示され、

すべて完了したら「処理完了」と表示されるようにしました。

 

これで、違う宛先に同じ文面で、それぞれの請求書ファイルを添付して送ることができました。

(下のテスト動画ではすべて自分宛に送っています)

 

すべてのコードはこちらです。


import sys
import openpyxl
from pathlib import Path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

#顧客マスタの読み込み
wb = openpyxl.load_workbook("顧客マスタ.xlsx")
ws = wb["Sheet1"]

customer_list = []

for row in ws.iter_rows(min_row=2):
  if row[0].value is None:
    break
  value_list = []
  for c in row:
    value_list.append(c.value)
  customer_list.append(value_list)
  
#請求書PDFのフォルダー
pdf_dir = "請求書PDF"

#メール送付リスト
mailing_list = []

#フォルダーから請求書のPDFファイルを1つずつ取得する
for invoice in Path(pdf_dir).glob("*.pdf"):
  #「顧客ID」は、PDFの拡張子を除いた部分
  customer_id = invoice.stem
  #該当する顧客データを「顧客マスタ」から検索
  for customer in customer_list:
    if customer_id == customer[0]:
      #メール送付リストに「顧客データ」とPDFファイルのパスを追加
      mailing_list.append([customer, invoice])

#メール本文を読み込む
text = open("mail_body.txt", encoding="utf-8")
body_temp = text.read()
text.close

#SMTPサーバー設定
smtp_server = "smtp.gmail.com"
port_number = 587

#ログイン情報
account = "*****@gmail.com"
password = "******"

#SMTPサーバーに接続
server = smtplib.SMTP(smtp_server, port_number)
server.starttls()
server.login(account, password)

#メール送付リストの顧客に1つずつメール送信
my_address = "Ryoko Tomura<****@*****.***>"
for data in mailing_list:
  customer = data[0]
  pdf_file = data[1]
  
  #メッセージの準備
  msg = MIMEMultipart()
  
  #件名、メールアドレスの設定
  msg["Subject"] = "ご請求書送付のご案内[*******会社]"
  msg["From"] = my_address
  msg["To"] = customer[4]
  
  #メール本文の追加
  body_text = body_temp.format(
    company=customer[1],
    department=customer[2],
    person=customer[3]
   )
  body = MIMEText(body_text)
  msg.attach(body)
  #添付ファイルの追加
  pdf = open(pdf_file, mode="rb")
  pdf_data = pdf.read()
  pdf.close
  attach_file = MIMEApplication(pdf_data)
  attach_file.add_header("Content-Disposition",
                         "attachement",filename=pdf_file.name)
  msg.attach(attach_file)
  
  #メール送信
  print("メール送信", customer[0], customer[1])
  server.send_message(msg)  
  
#SMTPサーバーとの接続を閉じる
server.quit
print("処理完了")

 

Pythonのメール自動化を試した所感

まず前提知識として、

  • モジュールのインポート
  • 変数、配列の知識
  • 繰り返し(for関数)

が必要と感じました。

やっていることはシンプルなのですが、

ある程度プログラミングの基礎知識がないと難しいと感じました。

とはいえ、コード自体は他の言語と比べるとわかりやすく、

順序立てて処理していけば、ノンエンジニアでもある程度のプログラムは

作れると思います。

 

以前、RPA(Win Automation)でもこのようなプログラムを作ったことがあります。

【RPA】Excel+WinAutomationで請求書作成・PDF化・定型文にてメール送付。

当然といえば当然ですが、やはりRPAの設定の方が楽に感じました。

RPAの場合にはメール送信に必要な情報はすべて

ダイアログボックスに入力していくことで完了するからです。

やはり1からプログラミングするのは骨が折れると感じました。

まずはRPAから試してみて、

慣れてきたらPythonに挑戦すると良いかもしれません。

 

もう一点注意したいのは、

こういったメール送信の自動化については

間違った宛先に送ってしまうと大問題ですので

まずは自分宛に何通か送ってみることをおすすめします。

 

請求書送付の他にも、

例えば支払明細書や支払調書の送付、

といった業務にも使えそうですね。

 

まとめ

Pythonでファイルを添付して複数の宛先へのメール(Gmail)送信を自動化する

方法をまとめました。

特に総務・経理などの部門では

日常的にこのような業務が発生するかと思いますので

是非参考にしてください。

 

編集後記

週末は、久しぶりに動物園へ。

望遠レンズでたくさん動物を撮ってきました。

 

最近のあたらしいこと

望遠レンズを持って動物園に

« »