Even though we live in an increasingly digital world, email communication remains a fundamental tool for many activities, both personal and professional. Automating the sending of emails can be particularly useful, and Python, with its simplicity and flexibility, offers an effective solution to achieve this operation.
In this article, we will explore how to send emails programmatically in Windows using Python, taking advantage of the win32com
library, which allows you to create personalized messages and send them easily using the default program installed in Windows.
We will also see how to configure your own script, manage repetitive operations and customize the content of emails, all with simple steps.
🔗 Do you like Techelopment? Check out the site for all the details!
Setup (Windows)
Let's start by installing the library that will allow us to create our email and open it in the default program (e.g. Outlook). Open the terminal (Win+r
type cmd
then Enter
) and launch the following command:
pip install pywin32
If the installation fails, you can try updating pip
:
pip install --upgrade pip
or install the main library that pywin32
is part of:
pip install pypiwin32
At this point we are ready to open our favorite IDE and start writing our python code, so let's start by importing the library:
import win32com.client as win32
Utility function
As we go through this article, we will define a series of functions that will help us organize the code to make it customizable and automatable. Let's see the most important one right away.
Build mail
object
def build_basic_email(subject, to_list, cc_list):
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = to_list
mail.CC = cc_list
mail.Subject = subject
return mail
build_basic_email
is a basic function that does nothing more than return the mail
object created with the wind32com
library. In this example the program used is Outlook.
Test Email
Let's now define a function to build a simple email so we can start getting familiar with the library:
def build_email_test(to, cc, auto=False):
subject = "My Subject"
mail = build_basic_email(subject, to, cc)
mail.HtmlBody = "test build mail programmatically"
print("opening the email in outlook, check the program")
mail.Display(True) # open in outlook
At this point we are ready to generate a test email:
import win32com.client as win32
def build_basic_email(subject, to_list, cc_list):
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = to_list
mail.CC = cc_list
mail.Subject = subject
return mail
def build_email_test(to, cc):
subject = "My Subject"
mail = build_basic_email(subject, to, cc)
mail.HtmlBody = "test build mail programmatically"
print("opening the email in outlook, check the program")
mail.Display(True) # open in outlook
if __name__ == "__main__":
build_email_test("test@test.com", "cc@cc.com")
Real Email to Automate
We can now delve into the creation of a python script that helps us automate our emails.
It often happens that emails have formatted text or even tables. That's why in this article we will see how to build a slightly more complex email like this:
Automation
Compared to the test example seen before, we will now introduce into our script also portions of code that will allow us to customize our email template without having to modify it by hand.
Let's start by adding a choice of email template to use:
import win32com.client as win32
if __name__ == "__main__":
email_type = input("Choose what kind of email to build:\n"
" 1. Techelopment\n"
" 2. test\n"
"> ")
email_type_disptacher(int(email_type))
The input
function in Python allows you to interact with the user by requesting input from the keyboard. When our script is complete we will get this result:
The email_type_dispatcher
function allows us to forward the request towards the construction of the template chosen by the user:
def email_type_disptacher(email_type):
to = getEmailAddresses("TO")
cc = getEmailAddresses("cc")
auto_send = input("automatic sending? [y/n] (default no): ")
send = True if auto_send == "y" else False
match email_type:
case 1:
build_email_Techelopment(to, cc, send)
case 2:
build_email_test(to, cc, send)
# In case there is no match
case _:
return -1
Let's see in detail what it does:
-
getEmailAddresses(..)
: this function allows us to ask the user for the email addresses to which to send the email -
auto_send
: we ask the user if (after having built the email) our script should proceed with automatic sending (without opening the classic Outlook window in which to modify the message).auto_send
will have a default value so as not to force the user to entery
orn
every time -
match email_type
: we use a switch to decide which code to execute based on the chosen template
Before moving on to the function that interests us most (build_email_Techelopment
), let's see how the getEmailAddresses(..)
function is made:
def getEmailAddresses(type_of_email="TO"):
emails = input(f"{type_of_email} (blank to use default addresses or 'e' to leave field empty): ")
if emails != "" and emails != 'e':
# more than one email address must be separated by ;
emails_splitted = emails.split("@")
while len(emails_splitted) > 2 and emails.count(';') < int(len(emails_splitted)/2):
print("use ; to separate addresses")
emails = input(f"{type_of_email} (blank to use default addresses or 'e' to leave field empty): ")
if emails == "" or emails == 'e':
break
return emails
This function asks the user to enter email addresses or leave blank (by hitting Enter
on the keyboard) to use the default value of the chosen template or type e
not to populate email addresses in case the user wants to manually enter them later.
The function handles multiple addresses by requesting and checking that they are separated by the ;
character.
Techelopment email template
Let's now see how our email is built with formatted text and the previously seen table.
The function that takes care of building and managing the Techelopment template is build_email_Techelopment
:
def build_email_Techelopment(to, cc, auto=False):
if to == "": # use default adresses
to = "ironman@ironman.com"
elif to == 'e': # leave field empty
to = ""
if cc == "": # use default adresses
cc = "avengers@avengers.com"
elif cc == 'e': # leave field empty
cc = ""
default_subject = 'New mission'
subject = input(f"Subject (blank for default '{default_subject}'): ")
if subject == "":
subject = default_subject
mail = build_basic_email(subject, to, cc)
body = f"<span style='font-family: Calibri; font-size:11pt;'>Hi, <br><br>NEW MISSION: <strong>follow Techelopment!</strong><br><br>Here the links<br><br>"
body += table_template.format(site_url='https://www.techelopment.it', fb_url='https://www.facebook.com/techelopment',
ig_url='https://instagram.com/techelopment', x_url='https://twitter.com/techelopment',
tg_url='https://t.me/techelopment_channel', wa_url='https://whatsapp.com/channel/0029VaoJHA1Lo4hkXn1rcn3y',
medium_url='https://medium.com/@techelopment', devto_url='https://dev.to/techelopment',
yt_url='https://youtube.com/@techelopment?si=UehAP3GeMeIkniEZ')
body += "<br><br>Regards</span><br><br>"
mail.HtmlBody = body + signature
manage_display_auto_send(mail, auto)
Let's see step by step how the email is built:
- The function takes as input the email addresses to be inserted in To and Cc. As you can see, the default case is handled with addresses defined directly in the function. The third parameter
auto
defines whether to automatically send the email or open the Outlook window to give the user the possibility of a final review.
N.B.
auto
is the parameter we built in theemail_type_dispatcher
function
- The email subject is set with a default and then asks the user if he wants to insert a specific one.
- The
mail
object is built with the classicbuild_basic_email
function seen previously - The body is the most substantial part (🙂) of our code because we will also have to manage the formatting. Let's see it in detail in the next paragraph.
-
manage_dispaly_auto_send
is a function that centralizes the management of automatic sending or opening of the email with Outlook
def manage_display_auto_send(mail, auto=False):
if auto:
print("sending email...")
mail.Send()
print("email sent 😎")
else:
print("opening the email in outlook, check the program")
mail.Display(True) # open in outlook
Techelopment Email Template Body
Since we intend to fully automate the construction of emails, in addition to the default values, keyboard inputs and automatic sending seen before, we will build the body using placeholders in order to parameterize the content of the email.
First, we initialize the body
variable with the introductory phrase of our email. For formatting, we can use CSS styling rules as they are mostly supported by Outlook:
body = (f"<span style='font-family: Calibri; font-size:11pt;'>"
f"Hi, <br><br>NEW MISSION: "
f"<strong>follow Techelopment!</strong>"
f"<br><br>Here the links<br><br>")
After that we move on to building the table:
body += table_template.format(
site_url='https://www.techelopment.it',
fb_url='https://www.facebook.com/techelopment',
ig_url='https://instagram.com/techelopment',
x_url='https://twitter.com/techelopment',
tg_url='https://t.me/techelopment_channel',
wa_url='https://whatsapp.com/channel/0029VaoJHA1Lo4hkXn1rcn3y',
medium_url='https://medium.com/@techelopment',
devto_url='https://dev.to/techelopment',
yt_url='https://youtube.com/@techelopment?si=UehAP3GeMeIkniEZ')
The table_template
variable contains the HTML code that builds the table to which we pass the values of the placeholders site_url
, fb_url
, ig_url
, x_url
, tg_url
, wa_url
, medium_url
, devto_url
, yt_url
.
table_template = '''
<table cellspacing="0" cellpadding="2" style="text-align:center;border:1px solid black; border-collapse: collapse; font-family: Calibri; font-size:11pt; vertical-align:top">
<tr style="border:1px solid black; vertical-align:top; padding:10px">
<td colspan="4" bgcolor="cadetblue" style="color:white;border:1px solid black; font-weight: bold; font-size:1.2em">
Techelopment <a href="{site_url}" style="color:white;">{site_url}</a>
</td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td bgcolor="cadetblue" width="100" style="color:white;border:1px solid black; font-weight: bold;">Social</td>
<td bgcolor="cadetblue" width="150" style="color:white;border:1px solid black; font-weight: bold;">Instant Messagging</td>
<td bgcolor="cadetblue" width="130" style="color:white;border:1px solid black; font-weight: bold;">Articles</td>
<td bgcolor="cadetblue" width="100" style="color:white;border:1px solid black; font-weight: bold;">Video</td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td style="border:1px solid black; font-style: italic; "><a href="{fb_url}">Facebook</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{tg_url}">Telegram</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{medium_url}">Medium</a> (italian)</td>
<td style="border:1px solid black; font-style: italic; "><a href="{yt_url}">Youtube</a></td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td style="border:1px solid black; font-style: italic;"><a href="{ig_url}">Instagram</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{wa_url}">WhatsApp</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{devto_url}">Dev.to</a> (english)</td>
<td style="border:1px solid black; font-style: italic; "></td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td style="border:1px solid black; font-style: italic;"><a href="{x_url}">X (ex twitter)</a></td>
<td style="border:1px solid black; font-style: italic; "></td>
<td style="border:1px solid black; font-style: italic; "></td>
</tr>
</table>'''
Finally we close the email construction with a signature and add everything to our mail
object:
body += "<br><br>Regards</span><br><br>"
mail.HtmlBody = body + signature
signature = '''
<br>
<div>
<b><span style='font-size:12.0pt;font-family:"Arial",sans-serif;color:gray;'>Techelopment</span></b>
<br>
<b><span style='padding:0px;font-size:10.0pt;font-family:"Arial",sans-serif;color:gray;'>TECHnology and devELOPMENT</span></b>
<br>
<span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:gray;'>
<a href="https://www.techelopment.it" target="_blank"><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:blue'>https://www.techelopment.it</span></a>
</span>
<br>
<span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:gray;'>E-mail: </span>
<span style='color:gray;'>
<a href="info@techelopment.it" target="_blank"><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:blue'>info@techelopment.it</span></a>
</span>
<br>
</div>
'''
Full script
Here is the full code and an example of execution:
import win32com.client as win32
signature = '''
<br>
<div>
<b><span style='font-size:12.0pt;font-family:"Arial",sans-serif;color:gray;'>Techelopment</span></b>
<br>
<b><span style='padding:0px;font-size:10.0pt;font-family:"Arial",sans-serif;color:gray;'>TECHnology and devELOPMENT</span></b>
<br>
<span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:gray;'>
<a href="https://www.techelopment.it" target="_blank"><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:blue'>https://www.techelopment.it</span></a>
</span>
<br>
<span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:gray;'>E-mail: </span>
<span style='color:gray;'>
<a href="info@techelopment.it" target="_blank"><span style='font-size:10.0pt;font-family:"Arial",sans-serif;color:blue'>info@techelopment.it</span></a>
</span>
<br>
</div>
'''
table_template = '''
<table cellspacing="0" cellpadding="2" style="text-align:center;border:1px solid black; border-collapse: collapse; font-family: Calibri; font-size:11pt; vertical-align:top">
<tr style="border:1px solid black; vertical-align:top; padding:10px">
<td colspan="4" bgcolor="cadetblue" style="color:white;border:1px solid black; font-weight: bold; font-size:1.2em">
Techelopment <a href="{site_url}" style="color:white;">{site_url}</a>
</td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td bgcolor="cadetblue" width="100" style="color:white;border:1px solid black; font-weight: bold;">Social</td>
<td bgcolor="cadetblue" width="150" style="color:white;border:1px solid black; font-weight: bold;">Instant Messagging</td>
<td bgcolor="cadetblue" width="130" style="color:white;border:1px solid black; font-weight: bold;">Articles</td>
<td bgcolor="cadetblue" width="100" style="color:white;border:1px solid black; font-weight: bold;">Video</td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td style="border:1px solid black; font-style: italic; "><a href="{fb_url}">Facebook</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{tg_url}">Telegram</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{medium_url}">Medium</a> (italian)</td>
<td style="border:1px solid black; font-style: italic; "><a href="{yt_url}">Youtube</a></td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td style="border:1px solid black; font-style: italic;"><a href="{ig_url}">Instagram</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{wa_url}">WhatsApp</a></td>
<td style="border:1px solid black; font-style: italic; "><a href="{devto_url}">Dev.to</a> (english)</td>
<td style="border:1px solid black; font-style: italic; "></td>
</tr>
<tr style="border:1px solid black; vertical-align:top; padding:7px">
<td style="border:1px solid black; font-style: italic;"><a href="{x_url}">X (ex twitter)</a></td>
<td style="border:1px solid black; font-style: italic; "></td>
<td style="border:1px solid black; font-style: italic; "></td>
</tr>
</table>'''
def manage_display_auto_send(mail, auto=False):
if auto:
print("sending email...")
mail.Send()
print("email sent 😎")
else:
print("opening the email in outlook, check the program")
mail.Display(True) # open in outlook
def build_basic_email(subject, to_list, cc_list):
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = to_list
mail.CC = cc_list
mail.Subject = subject
return mail
def build_email_Techelopment(to, cc, auto=False):
if to == "": # use default adresses
to = "ironman@ironman.com"
elif to == 'e': # leave field empty
to = ""
if cc == "": # use default adresses
cc = "avengers@avengers.com"
elif cc == 'e': # leave field empty
cc = ""
default_subject = 'New mission'
subject = input(f"Subject (blank for default '{default_subject}'): ")
if subject == "":
subject = default_subject
mail = build_basic_email(subject, to, cc)
body = (f"<span style='font-family: Calibri; font-size:11pt;'>"
f"Hi, <br><br>NEW MISSION: "
f"<strong>follow Techelopment!</strong>"
f"<br><br>Here the links<br><br>")
body += table_template.format(
site_url='https://www.techelopment.it',
fb_url='https://www.facebook.com/techelopment',
ig_url='https://instagram.com/techelopment',
x_url='https://twitter.com/techelopment',
tg_url='https://t.me/techelopment_channel',
wa_url='https://whatsapp.com/channel/0029VaoJHA1Lo4hkXn1rcn3y',
medium_url='https://medium.com/@techelopment',
devto_url='https://dev.to/techelopment',
yt_url='https://youtube.com/@techelopment?si=UehAP3GeMeIkniEZ')
body += "<br><br>Regards</span><br><br>"
mail.HtmlBody = body + signature
manage_display_auto_send(mail, auto)
def build_email_test(to, cc, auto=False):
subject = input("Subject: ")
mail = build_basic_email(subject, to, cc)
mail.HtmlBody = "test build mail programmatically"
manage_display_auto_send(mail, auto)
def getEmailAddresses(type_of_email="TO"):
emails = input(f"{type_of_email} (blank to use default addresses or 'e' to leave field empty): ")
if emails != "" and emails != 'e':
# more than one email address must be separated by ;
emails_splitted = emails.split("@")
while len(emails_splitted) > 2 and emails.count(';') < int(len(emails_splitted)/2):
print("use ; to separate addresses")
emails = input(f"{type_of_email} (blank to use default addresses or 'e' to leave field empty): ")
if emails == "" or emails == 'e':
break
return emails
def email_type_disptacher(email_type):
to = getEmailAddresses("TO")
cc = getEmailAddresses("cc")
auto_send = input("automatic sending? [y/n] (default no): ")
send = True if auto_send == "y" else False
match email_type:
case 1:
build_email_Techelopment(to, cc, send)
case 2:
build_email_test(to, cc, send)
# In case there is no match
case _:
return -1
if __name__ == "__main__":
email_type = input("Choose what kind of email to build:\n"
" 1. Techelopment\n"
" 2. test\n"
"> ")
email_type_disptacher(int(email_type))
Remember…
Unfortunately, basically, as long as the email window is open, you will not be able to interact with Outlook 🙄.
Follow me #techelopment
Official site: www.techelopment.it
Medium: @techelopment
Dev.to: Techelopment
facebook: Techelopment
instagram: @techelopment
X: techelopment
telegram: @techelopment_channel
youtube: @techelopment
whatsapp: Techelopment