Pythonを使うとエクセルのデータを読み込み、メールを個別送信することができます。
今回は顧客リストへ個別にメールを通知するプログラムを紹介します。
加えてただ単純にメール送信するだけではなく、ファイルを添付したり配信停止の顧客へ通知を控えたりすることも同時に行います。
・ファイルがあればOutlookメールに添付する
・配信停止のユーザーにはメールを送信しない
それでは以下で詳しく紹介していきます。
目次
- 1 ExcelデータをPythonで処理するプログラムの概要
- 2 Pythonプログラムを実行するための準備
- 3 Pythonプログラム解説
- 3.1 プログラム1|ライブラリの設定
- 3.2 プログラム2|outlookを起動
- 3.3 プログラム3|「customerlist.xlsx」を読み込む
- 3.4 プログラム4|エクセルファイルを読み込む
- 3.5 プログラム5|エクセルの各シートのデータを取得
- 3.6 プログラム6|「メールリスト」シートのデータを2行目~最終行で繰り返す
- 3.7 プログラム7|メール送信情報を取得
- 3.8 プログラム8|メールアドレスが配信停止かどうか調べる
- 3.9 プログラム9|配信停止であれば繰り返し処理をスキップする
- 3.10 プログラム10|「送信ドキュメント」シートとマッチング
- 3.11 プログラム11|グラフを表示
- 3.12 プログラム12|メール本文の{名前}を置換する
- 3.13 プログラム13|Outlookメールを作成
- 3.14 プログラム14|添付ファイルがあればメールに添付
- 3.15 プログラム15|メール送信
- 4 Pythonについて詳しく理解したいなら
ExcelデータをPythonで処理するプログラムの概要
今回はPythonで「Product」ごとにデータを解析してグラフを作成するプログラムを解説します。
実際に以下の作業をpythonで行うことを目指します。
1. Excelのデータを読み込む
2. 必要なテキストファイルや画像ファイルを取得する
3. 顧客ごとにメールを送信する
詳しいプログラム解説は後半で行います。
なお、今回使用するExcelはvlookupの関数を入れていたり、テキストファイルや画像ファイルを連携したりしています。
そのためファイルの保管場所によってはエラーが生じて上手くプログラムが動かないことが考えられます。
したがって、もし今回のプログラムをできるだけそのまま使いたい人のために一連のファイルをダウンロードしてそのまま使っていただけるようにします。
一連のファイルとは、Excel, テキストtext, 画像jpgです。Pythonファイルは入れていません。
以下のフォームからダウンロードできるので、必要な方はご活用ください。
formを入れる。
Pythonプログラムを実行するための準備
事前の準備としてopenpyxlとwin32comを使えるようにライブラリ設定をします。
準備1|openpyxlモジュールのインストール
1. コマンドプロンプトを起動(ショートカットキー[windows] + [R])
2. 「cmd」と記入して[Enter]
3. 「pip install openpyxl」と入力して[Enter]
4. インストール完了
これでインストールが完了し、openpyxlを使えるようになります。
準備2|win32com.clientモジュールのインストール
1. コマンドプロンプトを起動(ショートカットキー[windows] + [R])
2. 「cmd」と記入して[Enter]
3. 「pip install pywin32」と入力して[Enter]
4. インストール完了
これでインストールが完了し、win32com.clientを使えるようになります。
それでは以下でプログラムを解説していきます。
Pythonプログラム解説
この記事で紹介するプログラムを解説しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#プログラム1|ライブラリ設定 import openpyxl as px import win32com.client import os #プログラム2|outlookを起動 outlook = win32com.client.Dispatch("Outlook.Application") #プログラム3|「customerlist.xlsx」を読み込む filepath = 'customerlist.xlsx' #プログラム4|エクセルファイルを読み込む wb = px.load_workbook(filename=filepath) ws1 = wb['メールリスト'] ws2 = wb['送信ドキュメント'] ws3 = wb['配信停止'] #プログラム5|エクセルの各シートのデータを取得 sh1_values=[[cell1.value for cell1 in row1] for row1 in ws1] sh2_values=[[cell2.value for cell2 in row2] for row2 in ws2] sh3_values=[[cell3.value for cell3 in row3] for row3 in ws3] #プログラム6|「メールリスト」シートのデータを2行目~最終行で繰り返す for i in range(1, len(sh1_values)): # プログラム7|メール送信情報を取得 username = sh1_values[i][2] mailaddress = sh1_values[i][3] #プログラム8|メールアドレスが配信停止かどうか調べる flag = False for j in range(1, len(sh3_values)): if mailaddress == sh3_values[j][0]: flag = True break # プログラム9|配信停止であれば繰り返し処理をスキップする if flag==True: continue # プログラム10|「送信ドキュメント」シートとマッチング DocNo = sh1_values[i][4] for k in range(1,len(sh2_values)): if DocNo == sh2_values[k][0]: txtfile = sh2_values[k][1] attachmentfile = sh2_values[k][2] # プログラム11|メール件名、本文の取得 subject = txtfile.split('.')[1] with open(txtfile, mode='r') as f: body = f.read() break # プログラム12|メール本文の{名前}を置換する body = body.replace('{名前}',username) #プログラム13|Outlookメールを作成 mymail = outlook.CreateItem(0) mymail.BodyFormat = 3 mymail.To = mailaddress mymail.cc = "fastclassinfo@gmail.com" mymail.Subject = subject mymail.Body = body # プログラム14|添付ファイルがあればメールに添付 if attachmentfile != 'なし': attachment = os.path.abspath(attachmentfile) mymail.Attachments.Add (attachment) #プログラム15|メール送信 mymail.Send() print(f'{mailaddress}に「{subject}」を送信しました') |
以下で詳しく説明しています。
プログラム1|ライブラリの設定
1 2 3 4 |
#プログラム1|ライブラリの設定 import openpyxl as px import win32com.client import os |
プログラム解説
1 2 3 4 |
#解説 ・openpyxl|エクセルのデータ操作に使う ・win32com.client|Outlookでのメール送信に使う ・os|ファイルパスの指定に使う |
このプログラムでは、3つのライブラリ設定をします。
openpyxlは顧客リスト(Excel)のデータを取得するときに使います
win32com.clientはOutlookでメールを作成したり送信したりするときに使います。
osはメール添付時にフルパスを指定しないとメール送信が不安的になるときがあったため使います。
プログラム2|outlookを起動
1 2 |
#プログラム2|outlookを起動 outlook = win32com.client.Dispatch("Outlook.Application") |
プログラム解説
1 2 |
#解説 変数outlookでOutlookアプリケーションを呼び出す |
当然ですが、Outlookがパソコンにインストールされていないとメール送信はできません。
したがってOutlookを使える環境で使用することが条件です。
プログラム3|「customerlist.xlsx」を読み込む
1 2 |
#プログラム3|「customerlist.xlsx」を読み込む filepath = 'customerlist.xlsx' |
プログラム解説
1 2 |
#解説 変数filepathを「customerlist.xlsx」とする |
この事例では、対象のエクセルファイルをpythonプログラムと同じフォルダに保存してあります。
もしpythonを保存してあるフォルダと異なるフォルダのExcelファイルを結合したい場合は、「C:\Users\xxx\Dropbox\Python\Program\100_Excel\104_Excel_fileTenki」のようなフルパスを設定する方法があります。
プログラム4|エクセルファイルを読み込む
1 2 3 4 5 |
#プログラム4|エクセルファイルを読み込む wb = px.load_workbook(filename=filepath) ws1 = wb['メールリスト'] ws2 = wb['送信ドキュメント'] ws3 = wb['配信停止'] |
プログラム解説
1 2 3 4 5 |
#解説 変数wbで「filepath」のエクセルを読み込む 変数ws1を「メールリスト」シートに設定する 変数ws2を「送信ドキュメント」シートに設定する 変数ws3を「配信停止」シートに設定する |
プログラム3で設定したファイル名のエクセルを読み込んで、変数wbとして設定する
読み込んだエクセル内の各シートをws1, ws2, ws3とする。
プログラム5|エクセルの各シートのデータを取得
1 2 3 4 |
#プログラム5|エクセルの各シートのデータを取得 sh1_values=[[cell1.value for cell1 in row1] for row1 in ws1] sh2_values=[[cell2.value for cell2 in row2] for row2 in ws2] sh3_values=[[cell3.value for cell3 in row3] for row3 in ws3] |
1 2 3 4 |
#解説 変数sh1_valuesに「メールリスト」内のデータを取得 変数sh2_valuesを「送信ドキュメント」内のデータを取得 変数sh3_valuesを「配信停止」内のデータを取得 |
ここで取得した各シートのデータを使って、個別にメールを送信していきます。
プログラム6|「メールリスト」シートのデータを2行目~最終行で繰り返す
1 2 |
#プログラム6|「メールリスト」シートのデータを2行目~最終行で繰り返す for i in range(1, len(sh1_values)): |
プログラム解説
1 2 |
#解説 変数sh1_valuesのデータを1からlen(sh1_values)まで繰り返す |
今回扱うデータは、1行目にヘッダーが入っていて最終行15(No14)までの顧客リストです。
そのため、2行目から最終行15まで処理をしていくプログラムにする必要があります。
リストでは要素0にヘッダー情報が入っているため、range(1, len(sh1_values))とします。
range(0, len(sh1_values))とすると、ヘッダー部分もメール送信処理の対象になってしまうからです。
プログラム7|メール送信情報を取得
1 2 3 |
# プログラム7|メール送信情報を取得 username = sh1_values[i][2] mailaddress = sh1_values[i][3] |
プログラム解説
1 2 3 |
#解説 変数usernameにsh1_values[i行目][2列目]のセルデータを入れる 変数mailaddressにsh1_values[i行目][3列目]のセルデータを入れる |
A列|No|sh1_values[i][0]
B列|ユーザーID|sh1_values[i][1]
C列|名前|sh1_values[i][2]
D列|メールアドレス|sh1_values[i][3]
E列|Doc-No|sh1_values[i][4]
F列|送信メールファイル|sh1_values[i][5]
G列|添付ファイルURL|sh1_values[i][6]
プログラム8|メールアドレスが配信停止かどうか調べる
1 2 3 4 5 6 |
#プログラム8|メールアドレスが配信停止かどうか調べる flag = False for j in range(1, len(sh3_values)): if mailaddress == sh3_values[j][0]: flag = True break |
プログラム解説
1 2 3 4 5 6 |
#解説 変数flagをFalseにリセットする 配信停止シートのメールアドレスを一つずつ調べる: もし配信停止シートのメールアドレスと一致していれば: 変数flagをTrueに書き換える プログラム8の繰り返し処理を強制終了 |
ここでは配信停止したメールアドレスにメールを送信しないようする処理を入れています。
変数flagをFalseのままであれば、配信可能なメールアドレスと判断してプログラム9以降の処理を実行します。
プログラム9|配信停止であれば繰り返し処理をスキップする
1 2 3 |
#プログラム9|配信停止であれば繰り返し処理をスキップする if flag==True: continue |
プログラム解説
1 2 3 |
#解説 もし変数flagがTrueだったら continueでプログラム6に戻る |
配信停止シート内のメールアドレスとマッチングして、もし一致するものがあればプログラム9以降の処理を実行させず次の顧客リストのデータの処理を実行します。
プログラム10|「送信ドキュメント」シートとマッチング
1 2 3 4 5 6 |
#プログラム10|「送信ドキュメント」シートとマッチング DocNo = sh1_values[i][4] for k in range(1,len(sh2_values)): if DocNo == sh2_values[k][0]: txtfile = sh2_values[k][1] attachmentfile = sh2_values[k][2] |
プログラム解説
1 2 3 4 5 6 |
#解説 変数DocNoを「sh1_values[i][4]」のデータとする 送信ドキュメントシートのデータを1行ずつ読み込む: DocNoと送信ドキュメントのA列のデータが一致していれば 変数txtfileを「sh2_values[k][1]」とする 変数attachmentfileを「sh2_values[k][2]」とする |
本来であれば、「メールリスト」シートのF列やG列から送信メールファイルや添付ファイルURLを取得したかったが、openpyxlの仕様上、それが出来なかった。
というのも、今回使用している「メールリスト」シートのF列やG列はE列のDoc-Noをキーにして、「送信ドキュメント」シートのB列とC列を参照している。
つまり、「メールリスト」シートのF列とG列には数式が入っている。
残念なことに、openpyxlではセルに数式が入っている場合は、数式を取得してしまう。
したがって、openpyxlを使用する場合、数式が入っているセルの文字列を取得したい場合は、参照元である「送信ドキュメント」シートの値を取得せざるを得ない。
プログラム11|グラフを表示
1 2 3 4 5 |
# プログラム11|メール件名、本文の取得 subject = txtfile.split('.')[1] with open(txtfile, mode='r') as f: body = f.read() break |
プログラム解説
1 2 3 4 5 |
#解説 変数subjectに変数txtfileを「.」で区切ったときの1番目要素を取得 変数txtfileのテキストファイルをreadモードでfとして取得 変数bodyにテキストファイルの文言(メール本文)を取得 プログラム10の処理を強制終了 |
txtfile.split(‘.’)はtxtfileを「.(ピリオド)」でリストにすることができる。
たとえば、txtfile=「003.PythonとOutlookで効率化.txt」をprintでデバッグすると以下のようになる。
またtxtfileはPythonと同じフォルダに保管しておきます。
もし他のフォルダに保管しているテキストファイルを呼び出したい場合は、フルパスでtxtfileを指定します。
プログラム12|メール本文の{名前}を置換する
1 2 |
# プログラム12|メール本文の{名前}を置換する body = body.replace('{名前}',username) |
プログラム解説
1 2 |
#解説 本文内の{名前}をusernameに置換する |
個別メールで名前を入れることも多いので、名前を置換していきます。
置換する名前は「メールリスト」シートの名前列(username)で置換をします。
プログラム13|Outlookメールを作成
1 2 3 4 5 6 7 |
#プログラム13|Outlookメールを作成 mymail = outlook.CreateItem(0) mymail.BodyFormat = 3 mymail.To = mailaddress mymail.cc = "fastclassinfo@gmail.com" mymail.Subject = subject mymail.Body = body |
プログラム解説
1 2 3 4 5 6 7 |
#解説 変数mymailでメールを作成 メールの本文フォーマットを3(リッチテキスト)にする メールTo宛先を変数mailaddressにする メールcc宛先を"fastclassinfo@gmail.com"にする メール件名を変数subjectにする メール本文を変数bodyにする |
Outlookメールを作成し、これまでの情報をセットしていきます。
プログラム14|添付ファイルがあればメールに添付
1 2 3 4 |
#プログラム14|添付ファイルがあればメールに添付 if attachmentfile != 'なし': attachment = os.path.abspath(attachmentfile) mymail.Attachments.Add (attachment) |
プログラム解説
1 2 3 4 |
#解説 もし変数attachmentfileが「なし」でないならば 変数attachmentにattachmentfileのフルパスを設定 メールの添付ファイルにattachmentを追加 |
添付ファイルもPythonと同じフォルダに事前に保存しておく必要があります。
ここで敢えてフルパスを取得している理由は、プログラムを実行するなかでフルパスを取得しないとファイル添付が安定しなかったからです。
PCによっては相対パスで上手くいく場合もあるかもしれませんので、お使いのPCで試してみてください。
プログラム15|メール送信
1 2 3 |
#プログラム15|メール送信 mymail.Send() print(f'{mailaddress}に「{subject}」を送信しました') |
プログラム解説
1 2 3 |
#解説 メールを送信 メールのログを取得「mailaddress(メールアドレス)にsubject(メール件名)を送信しました') |
作成したメールを送付します。これはOutlookのアプリを起動していなくても送信可能です。
またメールのログを出力して送信先を確認します。
プログラムの解説はここまでです。
Pythonについて詳しく理解したいなら
Pythonを活用すると、仕事を効率化できる幅を広げることができます。
たとえば私が実際にPythonを活用して効率化してきた作業は以下の記事で紹介しています。
興味がある人は以下の記事もご覧ください。
Python×効率化のサンプル
Pythonで効率化できる事例をサンプルコード付きで紹介しています。
Python×Excel
PythonとExcelで自動化できることを紹介しています。
事例も数多く紹介しているので、ぜひ参考にしてみてください。
Python×PDF
PythonとPDFで自動化できることを紹介しています。
Python×フォルダ
Pythonって難しい?
Pythonの難易度などについては、以下で紹介しています。
勉強の参考になれば幸いです。