[Python] About creating a tool to create a new Outlook email based on the data of the JSON file and the part that got caught

1. About this article

The main purpose is Daily mail creation work, monthly regular mail, etc. I wanted to streamline routine work.

The second purpose is Handling of json files in Python I wanted to learn how to work with Outlook. (Frankly, if you just mess with Outlook Putting data in Excel and creating it with VBA I think it's the most dressed up)

[* Tools and source code are posted on Github (described later)](at the end of # 5)

2. What you want to do

・ Think about the items in the json file -Create a class that handles json files -Create a class to handle Office Outlook -Development of main method to create mail by linking the above classes

3. Tools / environment used

・ Windows 10 -Python 3.7.0 ・ Office2016 ・ Other various libraries described in the code below

4. Created code and explanation

Class diagram

The class diagram created by pycharm looks like this. OutlookMailCreater.png

Contents of json file

As a requirement, -Format (text mail, HTML mail, rich text) ・ Sender ・ Destination (multiple can be specified) ・ CC (multiple specifications allowed) ・ BCC (multiple specifications allowed) ·subject ·Text ・ Attachment I wanted something that could be set It became like this.

mailSetting.json


{
  "mailFormat": 3,
  "senderAddress": "[email protected]",
  "receiverAddressSet": ["[email protected]","[email protected]","[email protected]"],
  "CC_AddressSet": ["[email protected]","[email protected]"],
  "BCC_AddressSet": ["[email protected]","[email protected]"],
  "title":"AIUEO",
  "attachedFileFolderPath": "C:\\Users\\UserName\\Test",
  "body": "〇〇\n\n Thank you for your hard work. It is 〇〇.\n\I will send you n〇〇.\n\n or more.\n"
}

Choose mailFormat from numbers 1 to 3 Each seems to correspond to [text mail, HTML mail or rich text].

json handling class

JsonHandler.py


import json


class JsonHandler:
    def __init__(self, jsonPath):
        #Read json file
        self.file = open(jsonPath, 'r', encoding="utf-8_sig")
        self.jsonData = json.load(self.file)

    #Primary nest json data acquisition
    def getParam_OneNest(self, args):
        return self.jsonData[args]

    def __del__(self):
        #File close
        self.file.close()

Point (1): Encoding

I searched for an encoding method when importing a file, but I referred to this article. A story about having a hard time opening a file other than CP932 (Shift-JIS) encoded on Windows --Qiita

Apparently it is necessary to adopt the method of encoding = "utf-8_sig" for BOM processing.

outlook handling class

OutlookHandler.py



import glob
import os

import win32com.client


class OutlookHandler:
    def __init__(self):
        self.outlook = win32com.client.Dispatch("Outlook.Application")
        self.newMail = None

    def create(self):
        self.newMail = self.outlook.CreateItem(0)

    def setting(self, argMailformat, argSenderaddress,
                argReceiveraddressset, argCc_Addressset,
                argBcc_Addressset, argTitle,
                argAttachedfilefolderpath, argBody):

        # ///Information setting for mail items
        self.newMail.BodyFormat = argMailformat
        try:
            self.newMail._oleobj_.Invoke(*(64209, 0, 8, 0, self.outlook.Session.Accounts(argSenderaddress)))
        except:
            pass
        self.newMail.To = argReceiveraddressset
        self.newMail.cc = argCc_Addressset
        self.newMail.Bcc = argBcc_Addressset
        self.newMail.Subject = argTitle
        #Add signature to body (only when Outlook starts)
        try:
            self.newMail.Body = argBody \
                                + os.linesep \
                                + self.newMail.GetInspector.WordEditor.Bookmarks('_MailAutoSig').Range.Text
        except:
            self.newMail.Body = argBody

        #Get attachments
        if os.path.isdir(argAttachedfilefolderpath):
            for file in glob.glob(argAttachedfilefolderpath + '\\*'):
                if os.path.isfile(file):
                    self.newMail.Attachments.Add(file)

    def display(self):
        self.newMail.Display(False)

    def release(self):
        self.newMail = None
        self.outlook = None


Point (2): About setting the sender's email address

I'm doing this strange way.

self.newMail._oleobj_.Invoke(*(64209, 0, 8, 0, self.outlook.Session.Accounts(argSenderaddress)))

It was a standard in the case of VBA The "SentOnBehalfOfName" field couldn't be used for some reason (though it may be a configuration problem on the outlook side). When I looked it up, I found an article like this, so I adopted it. https://stackoverflow.com/questions/35908212/python-win32com-outlook-2013-sendusingaccount-return-exception

However, this method assumes that the address set in json is registered as the user's address in outlook. If it is not registered, an exception will occur, so try catch is used. It does not mean that you can use something that is not registered, such as SentOnBehalfOfName. Therefore, there is room for improvement. (If you use only the default address, there is no problem)

Point ③: How to put a signature on the text

self.newMail.Body = argBody \
                            + os.linesep \
                            + self.newMail.GetInspector.WordEditor.Bookmarks('_MailAutoSig').Range.Text  #Signature the text

With the method using the fields of WordEditor.Bookmarks like this, There is a big problem that "* signature is given only when the outlook application is started". If you execute the main method while it is not running, an exception will occur.

Therefore, this time, process it with try catch, If it's not running, I'll give up signing.

This is also a part that can be improved, but it can't be helped (because the outlook startup process is quite annoying).

main method

OutloookMailCreater.py


import datetime
import sys

#Reset module search path
#Make it possible to start by double-clicking
sys.path.append(r"C:\Users\UserName\PycharmProjects\CreateToolAndTest")
import os
import tkinter
from tkinter import messagebox
from PrivateTool.OutlookMailCreater.JsonHandler import JsonHandler
from PrivateTool.OutlookMailCreater.OutlookHandler import OutlookHandler
import traceback

if __name__ == '__main__':

    try:

        #message window preparation
        root = tkinter.Tk()
        root.withdraw()
        root.attributes("-topmost", True)

        #start outlook
        outlookHandler = OutlookHandler()
        outlookHandler.create()

        #json file manipulation object
        jsonHandler = JsonHandler(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mailSetting.json'))

        #Get the value from json and store it in the list
        settingList = [jsonHandler.getParam_OneNest('mailFormat'), ]
        settingList.append(jsonHandler.getParam_OneNest('senderAddress'))
        tempSet = jsonHandler.getParam_OneNest('receiverAddressSet')
        settingList.append('; '.join(tempSet))
        tempSet = jsonHandler.getParam_OneNest('CC_AddressSet')
        settingList.append('; '.join(tempSet))
        tempSet = jsonHandler.getParam_OneNest('BCC_AddressSet')
        settingList.append('; '.join(tempSet))
        settingList.append(jsonHandler.getParam_OneNest('title'))
        settingList.append(jsonHandler.getParam_OneNest('attachedFileFolderPath'))
        settingList.append(jsonHandler.getParam_OneNest('body'))

        #◆◆◆ If you want to add some processing to the list data, describe it here ◆◆◆
        # myDate = datetime.date.today()
        # if myDate.day < 16:
        #     myDate -= datetime.timedelta(days=15)
        # settingList[5] = settingList[5].replace('$date', myDate.strftime('%Y%m'))
        # ◆◆◆◆◆◆

        #Create new email item in outlook
        outlookHandler.setting(*settingList)

        #View mail items
        outlookHandler.display()
        outlookHandler.release()

        #announcement
        messagebox.showinfo("", "Successful completion")

    except:
        print("Error", messagebox.showinfo("Error", "Error occurred"))
        traceback.print_exc()
    finally:
        pass


Point ④: How to bring the message window to the front

It seems that you should set it as follows.

root.attributes("-topmost", True)

5. At the end

Click here for tools and source code ↓ CreateToolAndTest/Tool_Python/OutlookMailCreater at master · dede-20191130/CreateToolAndTest

Please comment if you have any supplements.

Recommended Posts

[Python] About creating a tool to create a new Outlook email based on the data of the JSON file and the part that got caught
[Python] About creating a tool to display all the pages of the website registered in the JSON file & where it got caught
[Python] Creating a tool that can list, select, and execute python files with tkinter & about the part that got caught
[Python] Create a script that uses FeedParser and LINE Notify to notify LINE of the latest information on the new coronavirus of the Ministry of Health, Labor and Welfare.
[Note] Based on the latitude and longitude of the CSV file, we created a script that extracts data in the target range and adds a mesh code.
A story that got stuck when trying to upgrade the Python version on GCE
[Python] A notebook that translates and downloads the ipynb file on GitHub into Japanese.
Python script to create a JSON file from a CSV file
Collect tweets about "Corona" with python and automatically detect words that became a hot topic due to the influence of "Corona"
Python --Read data from a numeric data file to find the covariance matrix, eigenvalues, and eigenvectors
[Python] Creating a GUI tool that automatically processes CSV of temperature rise data in Excel
[Python] A program to find the number of apples and oranges that can be harvested
Create a new csv with pandas based on the local csv
Build a Python environment and transfer data to the server
The story of making a tool that runs on Mac and Windows at the game development site
[Python scraping] Output the URL and title of the site containing a specific keyword to a text file
Create a shell script to run the python file multiple times
About Boxplot and Violinplot that visualize the variability of independent data
Python vba to create a date string for creating a file name
Dig the directory and create a list of directory paths + file names
[python] A note that started to understand the behavior of matplotlib.pyplot
[Python] A program that rotates the contents of the list to the left
[Python / Jupyter] Translate the comment of the program copied to the clipboard and insert it in a new cell
How to run the practice code of the book "Creating a profitable AI with Python" on Google Colaboratory
Introduction of "scikit-mobility", a library that allows you to easily analyze human flow data with Python (Part 1)
I tried to get and analyze the statistical data of the new corona with Python: Data of Johns Hopkins University
Use AWS lambda to scrape the news and notify LINE of updates on a regular basis [python]
Create a bot that posts the number of people positive for the new coronavirus in Tokyo to Slack
A story about creating a program that will increase the number of Instagram followers from 0 to 700 in a week
Upload data to s3 of aws with a command and update it, and delete the used data (on the way)
[Python] A program that calculates the number of socks to be paired
[Python] Create a linebot to write a name and age on an image
Test & Debug Tips: Create a file of the specified size in Python
How to create a wrapper that preserves the signature of the function to wrap
[Outlook] I tried to automatically create a daily report email with Python
I made a program to check the size of a file in Python
<Python> A quiz to batch convert file names separated by a specific character string as part of the file name
The story of creating Botonyan that returns the contents of Google Docs in response to a specific keyword on Slack
(Diary 1) How to create, reference, and register data in the SQL database of Microsoft Azure service with python
GAE --With Python, rotate the image based on the rotation information of EXIF and upload it to Cloud Storage.
Various ways to read the last line of a csv file in Python
[pyqtgraph] Understand SignalProxy and create a crosshair that follows the cursor on the graph
I tried to create a class that can easily serialize Json in Python
About the point that python 3.x got stuck due to an error due to caching_sha2_password
Python --Read data from a numeric data file and find the multiple regression line.
A Python script that reads a SQL file, executes BigQuery and saves the csv
Zip-compress any file with the [shell] command to create a file and delete the original file.
Create a BOT that displays the number of infected people in the new corona
Build a python environment to learn the theory and implementation of deep learning
I want to create a web application that uses League of Legends data ①
I made a tool to generate Markdown from the exported Scrapbox JSON file
[Python] A program that calculates the number of updates of the highest and lowest records
From Excel file to exe and release of tool that spits out CSV
A tool to insert the country name and country code in the IP address part
[Introduction to Python] How to get the index of data with a for statement