0% found this document useful (0 votes)
154 views

Using Python To Read and Save Your Outlook Emails! - by Alex Thines - Python in Plain English

This document provides instructions for using Python to read emails from Outlook and save them. It involves using the PyAutoGUI and win32com modules. The code uses PyAutoGUI to automate clicking through a terminal session to run the Python program. It then uses win32com to connect to Outlook and retrieve emails, printing out details like sender, subject, body. The emails are filtered based on subject lines listed in a monitor file. The goal is to programmatically back up or process emails for auditing purposes.

Uploaded by

Cristina Tessari
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
154 views

Using Python To Read and Save Your Outlook Emails! - by Alex Thines - Python in Plain English

This document provides instructions for using Python to read emails from Outlook and save them. It involves using the PyAutoGUI and win32com modules. The code uses PyAutoGUI to automate clicking through a terminal session to run the Python program. It then uses win32com to connect to Outlook and retrieve emails, printing out details like sender, subject, body. The emails are filtered based on subject lines listed in a monitor file. The goal is to programmatically back up or process emails for auditing purposes.

Uploaded by

Cristina Tessari
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

Open in app Sign up Sign In

Using Python to Read and Save Your Outlook


Emails!
Utilizing PyAutoGUI and win32com to read Outlook emails and save them to your
system.

Alex Thines · Follow


Published in Python in Plain English
15 min read · Aug 29

2
Photo by Brett Jordan on Unsplash

Use Case:

Downloading emails from Outlook and storing them so that you can trigger
other processes or securely back up emails for auditing purposes.

Getting started:

Python3

Pip3

pip3 install pyautogui

pip3 install keyboard

pip3 install pywin32

Periods of time where you are actively using your computer

Windows Operating System

Setup:

Install python along with PyAutoGui and pywin32. This specific use case and
program can only be used on Windows as we are accessing the via a
Windows Component Object Model (COM). This article is assuming you’ve
read my previous article here and would like to expand upon that idea (or
you were curious what emailReader.py was).
Part 1. PyAutoGUI:

The first portion of this is getting your clicking set up. This is going to be
extremely important as Window’s COM does not allow you to interact with it
via a scheduled task easily. Using baseBot.py found here, set up a series of
clicks to

1. Open a terminal

2. Go to the program’s directory

3. Run a python program

4. Wait for a set amount of time (I usually do 30 seconds to 1 minute


depending on the program and it’s average time to run.)

5. Close the program

To save time and to reuse perfectly good code, I will use the code at the end
of the PyAutoGui article as a starting point for this code.

import pyautogui
import logging
import keyboard
import time
import argparse
import sys

logging.basicConfig(level=logging.INFO)

# Set up logging
def get_arg():
""" Takes nothing
Purpose: Gets arguments from command line
Returns: Argument's values
"""
parser = argparse.ArgumentParser()
# Information
parser.add_argument("-d","--debug",dest="debug",action="store_true",help="Turn o
# Functionality
parser.add_argument("-f","--find",dest="find",action="store_true",help="Turn on
options = parser.parse_args()
if options.debug:
logging.basicConfig(level=logging.DEBUG)
global DEBUG
DEBUG = True
else:
logging.basicConfig(level=logging.INFO)
return options

def finder():
""" Takes nothing
Purpose: Finds the mouse position and color
Returns: Nothing
"""
while keyboard.is_pressed('q') != True:
if keyboard.is_pressed('c') == True:
x, y = pyautogui.position()
r,g,b = pyautogui.pixel(x, y)

logging.info("Mouse position: {}, {}. R: {}. G: {}. B: {}.".format(x, y,


logging.info("\twin32api.SetCursorPos(({}, {}))".format(x, y))
logging.info("\tpyautogui.pixel({}, {})[0] == {} and pyautogui.pixel({},
time.sleep(1)

def typeWriter(text):
""" Takes text
Purpose: Types out the text
Returns: Nothing
"""
if text == "ENTER":
pyautogui.press('enter')
else:
pyautogui.typewrite(text)
pyautogui.press('enter')

def clicker(x,y):
""" Takes x and y coordinates
Purpose: Clicks the location
Returns: Nothing
"""
pyautogui.click(x,y)

def main():
options = get_arg()
logging.info("Starting program")
if options.find:
finder()
sys.exit(1)

if pyautogui.pixel(1496, 1434)[0] in range(40,60) and pyautogui.pixel(1496, 1434


clicker(1496,1434) # Clicks the loction
time.sleep(3) # Wait for the program to load
typeWriter("cd testLocation") # Change to a different location
typeWriter("ENTER") # Press Enter
typeWriter("python emailReader.py") # Run emailReader.py program
typeWriter("ENTER") # Press Enter
time.sleep(60) # Wait 60 seconds
typeWriter("exit") # Close terminal
typeWriter("ENTER") # Press Enter
else:
logging.fatal("Color is not in range!") # Let user know that the color isn't i

if __name__ == "__main__":
main()

The above code s going to be the program that we call via a scheduled task.
While I am going to separate the code so that I can keep things more
organized, there is nothing wrong with adding an if statement to the above
code and making another argument call the win32com functionality we are
about to code.

Part 2. win32com:

This is where the more interesting part happens (and where we actually get
to exploit bypassing win32com’s restrictions).

Starting off, I like using this as my boilerplate:

import win32com.client
import win32com
import re

EMAILADDRESS = ""
IGNOREDSENDER = [""]

raw_emails = {}

with open("monitor.txt", "r") as f:


lines = f.readlines()
print(lines)

def main():
accounts, outlook = init()
emails = getEmails(accounts, outlook)
print(emails)

if __name__ == "__main__":
main()

The email address will be used for your email. Helpful if there are multiple
accounts on your system but only want to scrape one of them. Ignored
Sender is amazing if you have an automated system that sends emails that
you do not want this program to interact with. Monitor.txt is extremely
useful if you only care about emails with a certain subject line.

The next portion is the initialization portion. This is extremely short for this
use case but can get more complex if you use different COM systems
potentially.

def init():
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
accounts= win32com.client.Dispatch("Outlook.Application").Session.Accounts

return accounts, outlook

The “final” part is the actual meat and potatoes of this program. Since there
are many portions that do a lot of things and it can get extremely
confusing, I have made a lot of comments that explain what the line does
under it if I do not think it is completely obvious.
def getEmails(accounts, outlook):
"""Takes accounts and outlook
Purpose: Gets emails from outlook
Returns: Nothing
"""
# Counter used for counting the amount of emails per subject.
count = 0

# Loop through all accounts


for account in accounts:
# print("Account: {}".format(account))

# This is used if there are more than 1 account in outlook. If there are not
if str(account).lower() == EMAILADDRESS.lower():
print("Account: {}".format(account))
folders = outlook.Folders(account.DeliveryStore.DisplayName)
specific_folder = folders.Folders

# Loop through all folders


for folder in specific_folder:
#Prints the current folder you are in
print("Folder: '{}'".format(folder))
# Restricts the program to only check this folder. Useful if you are
if(folder.name == "Inbox"):
messages = folder.Items

# Loop through all messages


for single in messages:

# Check if the email subject is located in the monitor.txt f


for subject in lines:

# If statement looking for only those emails with the su


if subject.strip() in single.Subject.lower():
# Skipping emails that are from the ignored senders.
for sender in IGNOREDSENDER:
try:
if single.SenderName == sender.lower():
continue
except AttributeError:
pass
# I've found that certain email senders can cause is
try:
print("Sender: {}".format(single.Sender))
send = single.Sender
except AttributeError:
try:
print("Sender: {}".format(single.SenderName)
send = single.SenderName
except AttributeError:
print("Sender: {}".format(single.SenderEmailA
send = single.SenderEmailAddress

# Prints subject
print("Subject: {}".format(single.Subject))
# Prints when the email was received
print("Received Time: {}".format(single.ReceivedTime
# Prints if the email is unread or not
print("Unread: {}".format(single.Unread))

# This is used to get the body of the email. It will


loc = re.search("Confidentiality Notice", single.Bod
emailStart = re.search("From:\s", single.Body)

# This is used to show if one of them were found. If


print("Email Start: {}".format(emailStart))
print("Location: {}".format(loc))

# Checks to see which one was found first and uses t


if emailStart and not loc:
end = emailStart.start()
elif loc and not emailStart:
end = loc.start()
elif emailStart and loc:
end = min(emailStart.start(), loc.start())
else:
end = None

# Captures the body of the email until the establish


if end:
body = single.Body[:end]
body = body.replace("\r", "")
body = body.replace("\n\n", "\n")
body = body.strip()
print("Body:\n{}".format(body))

# Captures the entire email. If this is the first em


else:
body = single.Body
body = body.replace("\r", "")
body = body.replace("\n\n", "\n")
body = body.strip()
print("Body:\n{}".format(body))

# This regex is used for tracking the amount of emai


regex = re.compile(r"(Regex)")
name = re.findall(regex, str(single.Subject))
if name:
name = name[0].strip()
print("Name: {}".format(name))
if name in raw_emails:
print("Before Loop:{}".format(name))
count = int(0)
while name in raw_emails:
testName = name + "_" + str(count)
if testName not in raw_emails:
name = testName
print("After Loop:{}".format(name))
break
count += 1
print("During Loop:{}".format(name))

# Adds it to a dictionary so you can modify the data


raw_emails[name] = {"body": body.strip(), "subject":
# Seperate 1 email from another
print("-"*250+"\n\n")
# Prints all of the content
print(raw_emails)

# Converts the dictionary to a json file. Also replaces the single quotes with d
tmpEmails = raw_emails
tmpEmails = str(tmpEmails).replace('"', '|')
tmpEmails = str(tmpEmails).replace("'", '"')
tmpEmails = str(tmpEmails).replace("|", "'")

# Uncomment if you want it saved as a json file. You can also make this as a fla
# with open("emails.json", "w") as f:
# f.write(tmpEmails)

# Saves the emails to a text file.


with open("emails.txt", "w") as f:
for key, value in raw_emails.items():
f.write("ID: {}\n".format(key))
f.write("Subject: {}\n".format(value["subject"]))
f.write("Sender: {}\n".format(value["sender"]))
f.write("Recieved: {}\n".format(value["received"]))
f.write("Unread: {}\n".format(value["unread"]))
try:
f.write("Body:\n{}\n".format(value["body"]))
except UnicodeEncodeError as e:
f.write("Body:\n{}\n".format("{}".format(str(value["body"].encode("u
f.write("-"*250+"\n\n")

print("Finished Succesfully")
return raw_emails
The final program will look like this:

import win32com.client
import win32com
import re

EMAILADDRESS = ""
IGNOREDSENDER = [""]

raw_emails = {}

with open("monitor.txt", "r") as f:


lines = f.readlines()
print(lines)

def init():
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
accounts= win32com.client.Dispatch("Outlook.Application").Session.Accounts

return accounts, outlook

def getEmails(accounts, outlook):


"""Takes accounts and outlook
Purpose: Gets emails from outlook
Returns: Nothing
"""
# Counter used for counting the amount of emails per subject.
count = 0

# Loop through all accounts


for account in accounts:
# print("Account: {}".format(account))

# This is used if there are more than 1 account in outlook. If there are not
if str(account).lower() == EMAILADDRESS.lower():
print("Account: {}".format(account))
folders = outlook.Folders(account.DeliveryStore.DisplayName)
specific_folder = folders.Folders

# Loop through all folders


for folder in specific_folder:
#Prints the current folder you are in
print("Folder: '{}'".format(folder))
# Restricts the program to only check this folder. Useful if you are
if(folder.name == "Inbox"):
messages = folder.Items

# Loop through all messages


for single in messages:

# Check if the email subject is located in the monitor.txt f


for subject in lines:

# If statement looking for only those emails with the su


if subject.strip() in single.Subject.lower():
# Skipping emails that are from the ignored senders.
for sender in IGNOREDSENDER:
try:
if single.SenderName == sender.lower():
continue
except AttributeError:
pass
# I've found that certain email senders can cause is
try:
print("Sender: {}".format(single.Sender))
send = single.Sender
except AttributeError:
try:
print("Sender: {}".format(single.SenderName)
send = single.SenderName
except AttributeError:
print("Sender: {}".format(single.SenderEmailA
send = single.SenderEmailAddress

# Prints subject
print("Subject: {}".format(single.Subject))
# Prints when the email was received
print("Received Time: {}".format(single.ReceivedTime
# Prints if the email is unread or not
print("Unread: {}".format(single.Unread))

# This is used to get the body of the email. It will


loc = re.search("Confidentiality Notice", single.Bod
emailStart = re.search("From:\s", single.Body)

# This is used to show if one of them were found. If


print("Email Start: {}".format(emailStart))
print("Location: {}".format(loc))

# Checks to see which one was found first and uses t


if emailStart and not loc:
end = emailStart.start()
elif loc and not emailStart:
end = loc.start()
elif emailStart and loc:
end = min(emailStart.start(), loc.start())
else:
end = None

# Captures the body of the email until the establish


if end:
body = single.Body[:end]
body = body.replace("\r", "")
body = body.replace("\n\n", "\n")
body = body.strip()
print("Body:\n{}".format(body))

# Captures the entire email. If this is the first em


else:
body = single.Body
body = body.replace("\r", "")
body = body.replace("\n\n", "\n")
body = body.strip()
print("Body:\n{}".format(body))

# This regex is used for tracking the amount of emai


regex = re.compile(r"(Regex)")
name = re.findall(regex, str(single.Subject))
if name:
name = name[0].strip()
print("Name: {}".format(name))
if name in raw_emails:
print("Before Loop:{}".format(name))
count = int(0)
while name in raw_emails:
testName = name + "_" + str(count)
if testName not in raw_emails:
name = testName
print("After Loop:{}".format(name))
break
count += 1
print("During Loop:{}".format(name))

# Adds it to a dictionary so you can modify the data


raw_emails[name] = {"body": body.strip(), "subject":
# Seperate 1 email from another
print("-"*250+"\n\n")
# Prints all of the content
print(raw_emails)

# Converts the dictionary to a json file. Also replaces the single quotes with d
tmpEmails = raw_emails
tmpEmails = str(tmpEmails).replace('"', '|')
tmpEmails = str(tmpEmails).replace("'", '"')
tmpEmails = str(tmpEmails).replace("|", "'")
# Uncomment if you want it saved as a json file. You can also make this as a fla
# with open("emails.json", "w") as f:
# f.write(tmpEmails)

# Saves the emails to a text file.


with open("emails.txt", "w") as f:
for key, value in raw_emails.items():
f.write("ID: {}\n".format(key))
f.write("Subject: {}\n".format(value["subject"]))
f.write("Sender: {}\n".format(value["sender"]))
f.write("Recieved: {}\n".format(value["received"]))
f.write("Unread: {}\n".format(value["unread"]))
try:
f.write("Body:\n{}\n".format(value["body"]))
except UnicodeEncodeError as e:
f.write("Body:\n{}\n".format("{}".format(str(value["body"].encode("u
f.write("-"*250+"\n\n")

print("Finished Succesfully")
return raw_emails

def main():
accounts, outlook = init()
emails = getEmails(accounts, outlook)
print(emails)

if __name__ == "__main__":
main()

Limitations:

While I am personally extremely happy with this functionality, it is not


without its flaws. As mentioned in the previous PyAutoGui article, this
program requires you to not use your system during the time that it runs.
This causes massive scaling issues…

Once a day before work starts? That is fine.


Another time while you are out at lunch? Also fine.

Checking every 30 minutes or every hour while working? That is an issue…

If you need something in real time for updates, you will need another
system that you are not actively using for that. This can be achieved via a
dedicated Windows server or a windows Virtual Machine however.

Another interesting limitation is saving the emails when non basic latin
characters are present in the emails. This caused my original program to get
side tracked for roughly 2 hours while I was trying to sanitize a kanji email
signature…

In the end, I opted to have the entire email encoded to utf-8. In theory, you
can spend time calculating when the non latin characters start and when
they end. After that, you can encode just those characters and have the rest
of the email saved in their native format.

Why does this matter and why would I need this?

If you have gotten this far, I have to commend you on reading this far! When
I originally talked to my team and family about this idea, I was instantly
questioned about it since reading an email isn’t that hard. I always had to
explain to them the potential use cases for something like this.

Do you want to upload every email to Jira so that you can have the
information in a ticket for other analysts/testers/managers to see the entire
chain?

Do you want to parse every email into a database so that you have a more
in-depth knowledge base for a chatbot to respond with?

Do you want to send an email with through a Jira mail server or would you
prefer to send an email from a bot as if it was yourself?
These reasons (along with a few more client specific reasons) are why I
spent way too much time trying to figure out how to do everything listed in
the two programs above. Below I have included the code in their final forms.

If you get this far, thank you so much for taking the time to read this article
on “Using Python to read and save your Outlook emails!”

Until next time, Stay curious and Hack the Planet!

Code:

winBypass.py

import pyautogui
import logging
import keyboard
import time
import argparse
import sys

logging.basicConfig(level=logging.INFO)

# Set up logging
def get_arg():
""" Takes nothing
Purpose: Gets arguments from command line
Returns: Argument's values
"""
parser = argparse.ArgumentParser()
# Information
parser.add_argument("-d","--debug",dest="debug",action="store_true",help="Turn o
# Functionality
parser.add_argument("-f","--find",dest="find",action="store_true",help="Turn on

options = parser.parse_args()
if options.debug:
logging.basicConfig(level=logging.DEBUG)
global DEBUG
DEBUG = True
else:
logging.basicConfig(level=logging.INFO)
return options

def finder():
""" Takes nothing
Purpose: Finds the mouse position and color
Returns: Nothing
"""
while keyboard.is_pressed('q') != True:
if keyboard.is_pressed('c') == True:
x, y = pyautogui.position()
r,g,b = pyautogui.pixel(x, y)

logging.info("Mouse position: {}, {}. R: {}. G: {}. B: {}.".format(x, y,


logging.info("\twin32api.SetCursorPos(({}, {}))".format(x, y))
logging.info("\tpyautogui.pixel({}, {})[0] == {} and pyautogui.pixel({},
time.sleep(1)

def typeWriter(text):
""" Takes text
Purpose: Types out the text
Returns: Nothing
"""
if text == "ENTER":
pyautogui.press('enter')
else:
pyautogui.typewrite(text)
pyautogui.press('enter')

def clicker(x,y):
""" Takes x and y coordinates
Purpose: Clicks the location
Returns: Nothing
"""
pyautogui.click(x,y)

def main():
options = get_arg()
logging.info("Starting program")
if options.find:
finder()
sys.exit(1)
if pyautogui.pixel(1496, 1434)[0] in range(40,60) and pyautogui.pixel(1496, 1434
clicker(1496,1434) # Clicks the loction
time.sleep(3) # Wait for the program to load
typeWriter("cd testLocation") # Change to a different location
typeWriter("ENTER") # Press Enter
typeWriter("python emailReader.py") # Run emailReader.py program
typeWriter("ENTER") # Press Enter
time.sleep(60) # Wait 60 seconds
typeWriter("exit") # Close terminal
typeWriter("ENTER") # Press Enter
else:
logging.fatal("Color is not in range!") # Let user know that the color isn't i

if __name__ == "__main__":
main()

emailReader.py

import win32com.client
import win32com
import re

EMAILADDRESS = ""
IGNOREDSENDER = [""]

raw_emails = {}

with open("monitor.txt", "r") as f:


lines = f.readlines()
print(lines)

def init():
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
accounts= win32com.client.Dispatch("Outlook.Application").Session.Accounts

return accounts, outlook

def getEmails(accounts, outlook):


"""Takes accounts and outlook
Purpose: Gets emails from outlook
Returns: Nothing
"""
# Counter used for counting the amount of emails per subject.
count = 0

# Loop through all accounts


for account in accounts:
# print("Account: {}".format(account))

# This is used if there are more than 1 account in outlook. If there are not
if str(account).lower() == EMAILADDRESS.lower():
print("Account: {}".format(account))
folders = outlook.Folders(account.DeliveryStore.DisplayName)
specific_folder = folders.Folders

# Loop through all folders


for folder in specific_folder:
#Prints the current folder you are in
print("Folder: '{}'".format(folder))
# Restricts the program to only check this folder. Useful if you are
if(folder.name == "Inbox"):
messages = folder.Items

# Loop through all messages


for single in messages:

# Check if the email subject is located in the monitor.txt f


for subject in lines:

# If statement looking for only those emails with the su


if subject.strip() in single.Subject.lower():
# Skipping emails that are from the ignored senders.
for sender in IGNOREDSENDER:
try:
if single.SenderName == sender.lower():
continue
except AttributeError:
pass
# I've found that certain email senders can cause is
try:
print("Sender: {}".format(single.Sender))
send = single.Sender
except AttributeError:
try:
print("Sender: {}".format(single.SenderName)
send = single.SenderName
except AttributeError:
print("Sender: {}".format(single.SenderEmailA
send = single.SenderEmailAddress

# Prints subject
print("Subject: {}".format(single.Subject))
# Prints when the email was received
print("Received Time: {}".format(single.ReceivedTime
# Prints if the email is unread or not
print("Unread: {}".format(single.Unread))

# This is used to get the body of the email. It will


loc = re.search("Confidentiality Notice", single.Bod
emailStart = re.search("From:\s", single.Body)

# This is used to show if one of them were found. If


print("Email Start: {}".format(emailStart))
print("Location: {}".format(loc))

# Checks to see which one was found first and uses t


if emailStart and not loc:
end = emailStart.start()
elif loc and not emailStart:
end = loc.start()
elif emailStart and loc:
end = min(emailStart.start(), loc.start())
else:
end = None

# Captures the body of the email until the establish


if end:
body = single.Body[:end]
body = body.replace("\r", "")
body = body.replace("\n\n", "\n")
body = body.strip()
print("Body:\n{}".format(body))

# Captures the entire email. If this is the first em


else:
body = single.Body
body = body.replace("\r", "")
body = body.replace("\n\n", "\n")
body = body.strip()
print("Body:\n{}".format(body))

# This regex is used for tracking the amount of emai


regex = re.compile(r"(Regex)")
name = re.findall(regex, str(single.Subject))
if name:
name = name[0].strip()
print("Name: {}".format(name))
if name in raw_emails:
print("Before Loop:{}".format(name))
count = int(0)
while name in raw_emails:
testName = name + "_" + str(count)
if testName not in raw_emails:
name = testName
print("After Loop:{}".format(name))
break
count += 1
print("During Loop:{}".format(name))

# Adds it to a dictionary so you can modify the data


raw_emails[name] = {"body": body.strip(), "subject":
# Seperate 1 email from another
print("-"*250+"\n\n")
# Prints all of the content
print(raw_emails)

# Converts the dictionary to a json file. Also replaces the single quotes with d
tmpEmails = raw_emails
tmpEmails = str(tmpEmails).replace('"', '|')
tmpEmails = str(tmpEmails).replace("'", '"')
tmpEmails = str(tmpEmails).replace("|", "'")

# Uncomment if you want it saved as a json file. You can also make this as a fla
# with open("emails.json", "w") as f:
# f.write(tmpEmails)

# Saves the emails to a text file.


with open("emails.txt", "w") as f:
for key, value in raw_emails.items():
f.write("ID: {}\n".format(key))
f.write("Subject: {}\n".format(value["subject"]))
f.write("Sender: {}\n".format(value["sender"]))
f.write("Recieved: {}\n".format(value["received"]))
f.write("Unread: {}\n".format(value["unread"]))
try:
f.write("Body:\n{}\n".format(value["body"]))
except UnicodeEncodeError as e:
f.write("Body:\n{}\n".format("{}".format(str(value["body"].encode("u
f.write("-"*250+"\n\n")

print("Finished Succesfully")
return raw_emails

def main():
accounts, outlook = init()
emails = getEmails(accounts, outlook)
print(emails)

if __name__ == "__main__":
main()
In Plain English
Thank you for being a part of our community! Before you go:

Be sure to clap and follow the writer! 👏


You can find even more content at PlainEnglish.io 🚀
Sign up for our free weekly newsletter. 🗞️
Follow us on Twitter, LinkedIn, YouTube, and Discord.

Python Automation Windows Outlook Pyautogui

Alex
Thines

Written by Alex Thines


16 Followers · Writer for Python in Plain English

A simple hacker trying to learn as much as possible and share the lessons with everyone

More from Alex Thines and Python in Plain English

How to make report writing less miserable with Python


Alex Thines in Python in Plain English
Al

How to make report writing less miserable with Python


Using Microsoft Word, python, and the python- docx library to simplify report writing and
extracting information from reports.

7 min read · Aug 24

35 2

Wanna Code Like a Google Engineer? Let’s Dive into Advanced Python Together!

Builescu Daniel in Python in Plain English


B i

Wanna Code Like a Google Engineer? Let’s Dive into Advanced Python
Together!
Unlock the secrets of advanced Python, straight from an Ex- Googler! Dive into syntax, efficient
looping, magical libraries, and more. If…

· 21 min read · Aug 21

2.2K 10

10 Python Projects You Can Start Today and Monetize Tomorrow

Builescu Daniel in Python in Plain English


B i

10 Python Projects You Can Start Today and Monetize Tomorrow


🚀 💰
🔗
Dive into 10 Python projects with HUGE potential! Turn your code into cash. Ready to
unlock the magic?

· 20 min read · Aug 10

741 10

Did I just win $500 in gift cards or 5 fun presentations from the IT team?

Alex Thines
Al
Did I just win $500 in gift cards or 5 fun presentations from the IT team?
Understanding how to investigate an email to determine if it is phishing or not.

6 min read · Sep 5

See all from Alex Thines

See all from Python in Plain English

Recommended from Medium

Python PDF Editor

buzonliao in Python 101


b

Python PDF Editor


Explore the pypdf module for Python and discover how to manipulate PDF files. This guide
covers rotating text, merging PDF files, adding…

2 min read · Oct 12

Python Assert —Things I did not Know About

Varun Singh
V

Python Assert —Things I did not Know About


Most Python Developers don’t know these facts about Python assert statement. Python assert
is the most …

4 min read · Oct 8

69 1

Lists

Coding & Development


11 stories · 248 saves

Predictive Modeling w/ Python


20 stories · 547 saves

PrincipalTim Practical Guides to Machine Learning


Component
Seriele 10 stories · 626 saves
AnalysisAnalyc
New_ Reading_ List
Databricks 174 stories · 170 saves
role- based

Data Detective: Navigating Insights Through Exploratory Data Analysis

Parth Sojitra
P

Data Detective: Navigating Insights Through Exploratory Data Analysis


Unlock data’s secrets with Exploratory Data Analysis (EDA) — your compass to navigate the world
of insights.

7 min read · Oct 10

33

Datetime Module in Python

Gaurav Kumar
G

Datetime Module in Python


Python does not have standalone data types for representing dates and times. However, it
provides a built- in module called “datetime” that…

6 min read · Oct 21

18

Matplotlib vs Plotly Express: The Ultimate Python Data Visualization Brawl 🥊


Farhan Faiyaz
F

🥊
Matplotlib vs Plotly Express: The Ultimate Python Data Visualization Brawl

👑 Imagine the world of data visualization as a friendly game of chess. On one side sits the
seasoned champion, Matplotlib, with years of…

7 min read · Sep 18

58 1

📄 Python- docx: A Comprehensive Guide to Creating and Manipulating Word Documents in Python

Manoj Das
M

📄
Python-docx: A Comprehensive Guide to Creating and Manipulating Word
Documents in Python
Document Automation in Python.

6 min read · Sep 3

29 1

See more recommendations

You might also like