Pythonでやってみた11:メールリストからメールを一斉送信(Outlook)
概要
仕事柄複数メーカーに発注依頼しておりますが、客先都合で納期変更になったり、納入先詳細を別途連絡するなどで10社くらいに毎回メールを送付する必要が発生したため、「メーリングリストから一括でメール送付」するスクリプトをPythonで作成しました。
スクリプトおよびフォルダ構成は下記の通りです。
1.Excelでメーリングリスト作成
送付する件名、担当者、宛先(TO)、CC、対応(処理させるかどうか)をExcelでリスト化しており、注意点は下記の通りです。
下記がメーリングリストのサンプルです。前処理の効果が分かるように5,6行目に欠損値があるデータも追加しました。
なおリスト化作業は手動で実施したためかなり時間がかかりました。
2.メモ帳で送付したい本文を作成
次にメモ帳にメール本文を記載してファイルを保存します。宛名の”担当者様”に関して、”担当者”の部分を前章メーリングリストの「担当者名」に置換する予定であり、”様”が残る仕様になってます。
(継承の重複より継承漏れの方を防止したいため)
[メール本文.txt]
担当者様
お世話になります。KIYOです。
標記案件についてPJ納期を7月10日に変更したいため、
お手数をおかけしますが調整の方よろしくお願いいたします。
------------------------------------------------
署名欄
note
KIYO
-----------------------------------------------
3.リスト・メモ帳の情報抽出/前処理
3-1.前処理の全コード
本章の完成コードは下記の通りです。大きく分けて①必要ライブラリのインポート、②メール本文用のテキスト情報取得、③メーリングリストから宛先に値がある行だけ取得 しています。
[IN]
import glob
import os
import re
import pandas as pd
import smtplib, ssl, os
from email.mime.text import MIMEText
import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.base import MIMEBase
from email import encoders
#ファイルパス
path_text = 'メール本文.txt'
path_maillist = 'メール送付.xlsx'
#メール本文を取得
with open(path_text, 'r', encoding='utf-8') as f:
text = f.read()
df = pd.read_excel(path_maillist)
df = df.dropna(subset=['TO']) #宛先に値がない行は削除
# df = df[df['対応'] == 'Not Done'] #対応が未完の物だけ抽出する場合
df
[OUT]
3-2.メモ帳の本文取得:with open()
ファイル情報取得するにはPythonの組み込み関数であるopen()を使用します。メモ帳はutf-8で作成したためencoding引数にutf-8を渡しました。
結果のとおり、現状では宛名は”担当者様”のままです。
[IN]
path_text = 'メール本文.txt'
#メール本文を取得
with open(path_text, 'r', encoding='utf-8') as f:
text = f.read()
print(text)
[OUT]
担当者様
お世話になります。KIYOです。
標記案件についてPJ納期を7月10日に変更したいため、
お手数をおかけしますが調整の方よろしくお願いいたします。
------------------------------------------------
署名欄
note
KIYO
-----------------------------------------------
3-3.メーリングリストの取得:pandas
メーリングリストは表形式で使用できるようにpd.read_excel()でデータ取得後にdropna()でTOカラムに値がない行は削除しました。
[IN]
df = pd.read_excel(path_maillist)
df = df.dropna(subset=['TO']) #宛先に値がない行は削除
df
[OUT]
条件抽出を追加することで「対応がNot Done」の行だけ抽出できます。
[IN]
df = pd.read_excel(path_maillist)
df = df.dropna(subset=['TO']) #宛先に値がない行は削除
df = df[df['対応'] == 'Not Done'] #対応が未完の物だけ抽出する場合
df
[OUT]
今回は送付漏れがないかの確認もしたいため、完成コードで条件抽出はコメントアウトにしております。
4.For分でメーリングリストの情報抽出
本章ではsmtplibに渡す値をメーリングリストから抽出していきます。前処理も含めて処理ポイントは下記の通りです。
[IN]
for idx, data in df.iterrows():
_subject = data['件名']
name_To = data['担当者名']
To_send = data['TO']
CC_send = data['CC']
#CCが空の時は型式がfloatになるため空文字を追加
if pd.isna(CC_send):
CC_send = ''
finished = data['対応']
subject = '【依頼】' + '納期変更_' + _subject + '_Xプロジェクト' #件名の作成
maintext = re.sub('担当者', name_To, text) #宛名を置換
print(subject)
print(maintext)
#対応がNot Doneの場合は処理
if finished == 'Not Done':
df.loc[idx]['対応'] = 'Done' #Not Done->Doneに変更※元ファイルは変更無し
df
[OUT]
【依頼】納期変更_ABC-製品X_Xプロジェクト
担当A様
お世話になります。KIYOです。
標記案件についてPJ納期を7月10日に変更したいため、
お手数をおかけしますが調整の方よろしくお願いいたします。
------------------------------------------------
署名欄
note
KIYO
-----------------------------------------------
【依頼】納期変更_XYZ-製品D_Xプロジェクト
担当B様
お世話になります。KIYOです。
標記案件についてPJ納期を7月10日に変更したいため、
お手数をおかけしますが調整の方よろしくお願いいたします。
------------------------------------------------
署名欄
note
KIYO
-----------------------------------------------
【依頼】納期変更_DD-製品トライアル_Xプロジェクト
担当C様
お世話になります。KIYOです。
標記案件についてPJ納期を7月10日に変更したいため、
お手数をおかけしますが調整の方よろしくお願いいたします。
------------------------------------------------
署名欄
note
KIYO
-----------------------------------------------
5.smtplibでメール送付
最後にsmtplibライブラリを使用してメールを送付します。なお使用するソフトはOutlookで作成しております。
5-1.smtplib関数の作成
メール送付用の関数をsmtplibで作成しました。流れは下記の通りです。
[IN]
account = 'KIYO@outlook' #自分のメールアドレス
password = 'note123456789' #メールのパスワード
def messageinfo(subject:str, To_send:str, CC_send:str, text:str):
#メールデータを作成
msg = MIMEMultipart()
msg['Subject'] = subject #件名
msg['To'] = To_send #宛先
msg['From'] = account #差出人
msg['Cc'] = CC_send #CC
#テキストを追加
bodytext = text #メモ帳の中身を記載
txt = MIMEText(bodytext)
msg.attach(txt)
#Excelを添付する場合に使用
# path_attach = path_maillist
# attachment = MIMEBase('application', 'vnd.ms-excel')
# with open(path_attach, 'rb') as fp:
# attachment.set_payload(fp.read())
# encoders.encode_base64(attachment)
# attachment.add_header("Content-Disposition",
# "attachment", filename=os.path.basename(path_attach))
# msg.attach(attachment)
return msg
def send_outlook_mail(msg):
server = smtplib.SMTP('smtp.office365.com', 587)
server.ehlo()
server.starttls()
server.ehlo()
server.login(
account,
password
)
server.send_message(msg)
5-2.メール処理
5-1節の関数と4章のコードを使用してメールを送付します。
”input()"は実行後に手動で値を入力する関数でありメール誤送信防止用として追加しました。下記コードでは実行後に"123"と入力すれば処理が開始してメールが送付されます。
なお送付前の確認をしたい場合は「messageinfo」と「send_outlook_mail」をコメントアウトしておけば実行してもメール送付はされません。
[IN]
#メールを送付
sendpass = input() #誤送信防止:手動でパスワードを入力※出力:str
print('メール送信用のパスワードを入力してください。')
if sendpass=='123':
for idx, data in df.iterrows():
_subject = data['件名']
name_To = data['担当者名']
To_send = data['TO']
CC_send = data['CC']
#CCが空の時は型式がfloatになるため空文字を追加
if pd.isna(CC_send):
CC_send = ''
finished = data['対応']
subject = '【依頼】' + '納期変更_' + _subject + '_Xプロジェクト' #件名の作成
maintext = re.sub('担当者', name_To, text) #宛名を置換
#対応がNot Doneの場合は処理
if finished == 'Not Done':
df.loc[idx]['対応'] = 'Done' #Not Done->Doneに変更※元ファイルは変更無し
msg = messageinfo(subject, To_send, CC_send, text=maintext) #メール送信情報作成
send_outlook_mail(msg) #メール送付
display(df)
6.完成コード
完成コードは下記の通りです。Jupyterで使用することを想定してブロックを2つに分けました。
[IN]
import glob
import os
import re
import pandas as pd
import smtplib, ssl, os
from email.mime.text import MIMEText
import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.base import MIMEBase
from email import encoders
#ファイルパス
path_text = 'メール本文.txt'
path_maillist = 'メール送付.xlsx'
#メール本文を取得
with open(path_text, 'r', encoding='utf-8') as f:
text = f.read()
df = pd.read_excel(path_maillist)
df = df.dropna(subset=['TO']) #宛先に値がない行は削除
# df = df[df['対応'] == 'Not Done'] #対応が未完の物だけ抽出する場合
df
[IN]
account = 'KIYO@outlook' #自分のメールアドレス
password = 'note123456789' #メールのパスワード
def messageinfo(subject:str, To_send:str, CC_send:str, text:str):
#メールデータを作成
msg = MIMEMultipart()
msg['Subject'] = subject #件名
msg['To'] = To_send #宛先
msg['From'] = account #差出人
msg['Cc'] = CC_send #CC
#テキストを追加
bodytext = text #メモ帳の中身を記載
txt = MIMEText(bodytext)
msg.attach(txt)
#Excelを添付する場合に使用
# path_attach = path_maillist
# attachment = MIMEBase('application', 'vnd.ms-excel')
# with open(path_attach, 'rb') as fp:
# attachment.set_payload(fp.read())
# encoders.encode_base64(attachment)
# attachment.add_header("Content-Disposition",
# "attachment", filename=os.path.basename(path_attach))
# msg.attach(attachment)
return msg
def send_outlook_mail(msg):
server = smtplib.SMTP('smtp.office365.com', 587)
server.ehlo()
server.starttls()
server.ehlo()
server.login(
account,
password
)
server.send_message(msg)
#メールを送付
sendpass = input() #誤送信防止:手動でパスワードを入力※出力:str
print('メール送信用のパスワードを入力してください。')
if sendpass=='123':
for idx, data in df.iterrows():
_subject = data['件名']
name_To = data['担当者名']
To_send = data['TO']
CC_send = data['CC']
#CCが空の時は型式がfloatになるため空文字を追加
if pd.isna(CC_send):
CC_send = ''
finished = data['対応']
subject = '【依頼】' + '納期変更_' + _subject + '_Xプロジェクト' #件名の作成
maintext = re.sub('担当者', name_To, text) #宛名を置換
#対応がNot Doneの場合は処理
if finished == 'Not Done':
df.loc[idx]['対応'] = 'Done' #Not Done->Doneに変更※元ファイルは変更無し
msg = messageinfo(subject, To_send, CC_send, text=maintext) #メール送信情報作成
send_outlook_mail(msg) #メール送付
display(df)
参考資料1:コードに使用
参考資料2:改善用
あとがき
さらに下記ができると使いやすいけど、とりあえず自分だけで使うしさっとと使いたかったのでパパっと作成しました。
誰か改善してくれると嬉しい
この記事が気に入ったらサポートをしてみませんか?