はじめに
初学者がPythonを勉強しています。
間違っている内容や改善などご教示いただければ幸いです。
目的
(共通)Pythonを学習するにあたり、まずは身近にある業務の省人化を目的とする。
(今回)メールは送受信する必要があり、「自動送信、できれば添付ファイル送信できるといいよね。」
→通常業務でまだ残るZIP,PW文化。仕方ないからZIP,PW添付させよう。
PW部は処理重複するため、一部抜粋とした
目標
基本的なコード理解と実際の成功体験を得る
継続的な学習へ繋げる
理解力の深掘り、さらなるコード改善に繋がればなおよし
流れ
- あるフォルダの中に存在する全ファイルからZIPファイルを生成
- ZIPファイルを添付し、メール送信文書を作成
- 送信内容を確認後、自動送信
- HAPPY!
*22.11.08時点 残念ながら現在はメール内容はテンプレのみ。初学者ですので。。。
環境
Windows10
Python 3.8.3 (memo: python -V
参考にさせていただいたサイト、記事など
大変参考になりました。感謝いたします。
全体コード
以下、全体コード
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.base import MIMEBase
from email import encoders
import win32com.client
#get Date
import datetime
import time
import os
import zipfile
import shutil
#zippw
import pyminizip
import string
import secrets
#GUI : message box
from tkinter import messagebox
import tkinter as tk
import sys
# アカウント
my_account = 'hogehoge1'
my_password = 'hogehoge2'
mail_address = 'hogehoge3'
#メール送信func
def send_outlook_mail(msg,body,src_file_names):
try:
# Check GUI
root = tk.Tk()
root.withdraw()
# Check Contents & Attachment
ret = messagebox.askyesno('Check','-----------------------------件名-----------------------------\n\n'+str(msg['Subject'])+'\n\n-----------------------------To-----------------------------\n\n'+str(msg['To'])+'\n\n-----------------------------Bcc-----------------------------\n\n'+str(msg['Bcc'])+'\n\n-----------------------------本文-----------------------------\n\n'+body+'\n\n---------------------添付ファイル-----------------------------\n\n'+str(src_file_names))
# もし確認内容が異なるなら、終了
if ret == False:
sys.exit()
"""
引数msgをOutlookで送信
"""
server = smtplib.SMTP(' ', portnum)
server.ehlo()
server.starttls()
server.ehlo()
# ログインしてメール送信
server.login(my_account, my_password)
#Send mail
server.send_message(msg)
print('send OK')
server.quit()
#Exception
except Exception as E:
print("***** エラー内容 *****")
print("type: "+ str(type(E)))
print("args: " + str(E.args))
print("message: " + E.message)
print("E: " + str(E))
print('False')
return False
def make_mime(mail_to, mail_bcc, subject, body):
"""
引数をMIME形式に変換
"""
msg = MIMEMultipart() #メッセージ本文
msg['Subject'] = subject #件名
msg['To'] = mail_to #宛先
msg['Bcc'] = mail_bcc #宛先
msg['From'] = mail_address #送信元
msg.attach(MIMEText(body))
print('Check make_mime')
return msg
#ファイル添付func
def func_attachment(zip_file_name,msg):
# attachment zip file
attach = MIMEBase('application','zip')
with open(zip_file_name, "br") as f:
attach.set_payload(f.read())
encoders.encode_base64(attach)
attach.add_header('Content-Disposition', 'attachment', filename=today + 'attachment.zi_')
msg.attach(attach)
print('Finish Attachment')
#PW生成
def generate_pw():
#Complex PW
pass_chars = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(pass_chars) for x in range(10))
return password
#ファイル一覧取得
def get_file_path(file_path):
"""
ファイルパスから指定以下のファイルの一覧を取得する
:param file_path:ファイルパス
:return: generator
"""
if os.path.isfile(file_path):
yield file_path
else:
for (base_dir, _ , file_name_list) in os.walk(file_path):
for file_name in file_name_list:
path = os.path.join(base_dir, file_name)
path = path.replace(os.sep, '/')
yield path
#zipファイル作成
def zipping(file_path, save_dir,pw):
"""
ファイル及びフォルダごとZIP化関数
:param file_path: 圧縮対象のファイルおよびディレクトリ
:param save_dir: 保存先(デフォルトは圧縮対象と同じ階層)
:return:
"""
if file_path[-1]==os.sep or file_path[-1]=="/" :
file_path = file_path[:-1]
if not os.path.isdir(file_path) and not os.path.isfile(file_path):
print("Not Found : {}".format(file_path))
raise FileNotFoundError
if os.path.isdir(save_dir):
save_dir = os.path.join(save_dir, os.path.basename(file_path))
else:
save_dir = file_path
zip_file_name = "{}.zip".format(save_dir)
print('zip file : {}'.format(zip_file_name))
src_file_names = ["%s\\%s" % (file_path, name) for name in os.listdir(file_path)]
#パスワード付きZIP File generated..
print('Check len(src_file_names)->..... ' + str(len(src_file_names)))
#pfx_file_names = ['' for i in len(src_file_names)]
#for prefix apeend ''
pfx_file_names =[]
for i in range(len(src_file_names)):
pfx_file_names.append('')
print('Check pfx_file_names->..... ' +str(pfx_file_names))
#ZIP圧縮 pyminizip.compress_multiple(src_file_names,pfx_file_names,zip_file_name.encode('cp932'),pw.encode('cp932'),int(0))
print('zip compressed')
'''
one file only -> OK!
pyminizip.compress(str(file_name),'',str(zip_file_name),"hogehoge", int(0))
'''
print('Finish zipping')
print('zip_file_name: '+ zip_file_name+ '\n')
return zip_file_name
#メイン処理部
def my_message(i,pw):
#Make Zipfile.
file_path = ''
#Path Check(~/Desktop )
save_path = os.path.expanduser('~/Desktop')
print('save_path->..... '+ save_path)
#i=1 -> Mainメッセージ, i=2 -> PW部
if i ==1:
#for send_outlook_mail(check attachmentfile)
src_file_names = ["%s\\%s" % (file_path, name) for name in os.listdir(file_path)]
#ファイル名で本文を変更
#aaa ある場合-> aaaフォーム
#bbb ある場合-> bbbフォーム
l_in = [s for s in src_file_names if 'aaa' in s]
l_in = [s for s in src_file_names if 'bbb' in s]
# MIME形式に変換
if 'aaa' in str(l_in):
body=' ******* This mail is AutoSend:'+ now +' .... '
msg = make_mime(
mail_to='', #送信したい宛先を指定
mail_bcc =mail_address,
subject='',body=body )
elif 'bbb' in str(l_in):
body=' ******* This mail is AutoSend:'+ now +'... '
msg = make_mime(
mail_to='', #送信したい宛先を指定
mail_bcc =mail_address,
subject='',body=body)
else:
body=' ******* This mail is AutoSend:'+ now +'... '
msg = make_mime(
mail_to='', #送信したい宛先を指定
mail_bcc =mail_address,
subject='',body=body)
#zip処理させる関数
file = zipping(file_path,save_path,pw)
#fileを添付させる関数
func_attachment(file,msg)
#send mail
result = send_outlook_mail(msg,body,src_file_names)
#ファイルの有無確認後、あれば削除
if os.path.isfile(save_path+hoge.zip):
os.remove(save_path+'\\tmp.zip')
#メイン
if __name__ == '__main__':
#PW自動生成
pw = generate_pw()
#Send main contents (i==1)
my_message(1,pw)
#PW送信(i==2)
my_message(2,pw)
今後の課題(雑感多め)
【全体】
可続性、メンテ性を考慮した記述方式を確立(他者へ説明できるレベルで自分なりの納得)
【細かい箇所】
コメントアウトのクオリティ(誰が見てもすぐ判断がつくように。)
メール本文などを添付ファイル名称からテンプレ(DB)識別させた方が良い。
今回はOUTPUT優先。
(保留)C言語との違いもあり、さらなる理解が必要(ただし現状はOUTPUTを先行
(保留)if分のエラー処理の記述内容が明確に理解できていない所もある。
エラー内容は、エラーを吐いた時点で学習していく)
(保留)現状はメール送信前の確認インタフェースで間違いが無いか確認しているが、他のスマートな手法は?
次の展開
目的に沿って、次の業務改善に繋がるプログラムを作成する
OUTPUT継続
最後に
長文、乱文となりましたがお付き合いありがとうございました。