1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PythonでZIPファイル作成後、メール添付送信

Posted at

はじめに

初学者がPythonを勉強しています。
間違っている内容や改善などご教示いただければ幸いです。

目的

(共通)Pythonを学習するにあたり、まずは身近にある業務の省人化を目的とする。
(今回)メールは送受信する必要があり、「自動送信、できれば添付ファイル送信できるといいよね。」
→通常業務でまだ残るZIP,PW文化。仕方ないからZIP,PW添付させよう。
 PW部は処理重複するため、一部抜粋とした

目標

基本的なコード理解と実際の成功体験を得る
継続的な学習へ繋げる
理解力の深掘り、さらなるコード改善に繋がればなおよし

流れ

  1. あるフォルダの中に存在する全ファイルからZIPファイルを生成
  2. ZIPファイルを添付し、メール送信文書を作成
  3. 送信内容を確認後、自動送信
  4. HAPPY!

*22.11.08時点 残念ながら現在はメール内容はテンプレのみ。初学者ですので。。。

環境

Windows10
Python 3.8.3 (memo: python -V

参考にさせていただいたサイト、記事など

大変参考になりました。感謝いたします。

全体コード

以下、全体コード

sendmail_zip.py
#!/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継続

最後に

長文、乱文となりましたがお付き合いありがとうございました。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?