Bulk mail - israel-dryer/Outlook-Python-Tutorial GitHub Wiki

So, you want to send bulk mail from Outlook? Technically, you cannot send bulk mail from Outlook because of the sending limits, but there are some methods that you can use to work around them. The most challenging limit is the 30 emails per minute limit. From my experience, you can send more than 30 per minute through your Outbox, but they will not be delivered to the recipient at a rate faster than 30 per minute. Also, you want to avoid pushing thousands of emails to your Outbox at once because it can cause Outlook to become unresponsive and crash... potentially eating away all your time savings by having to restart. I've been able to successfully push about 100 emails per minute and keep everything running smoothly. However, for this example, I'm going to push the emails through the Outbox at a rate of 30 per minute, which is the same rate at which they will be delivered.

Method 1 - Create and send (single-step)

With this method, the emails are created and then sent at a rate of 30 per minute by using a timer. It's very simple to implement and easy to understand. I have a list of fake emails that I'm going to use as an example which contains a name and email address for approximately 48 individuals.

import csv
from time import sleep
import win32com.client as client

# create template for message body
template = "{}, please submit your time as soon as possible!"

# open distribution list
with open('people.csv', 'r', newline='') as f:
    reader = csv.reader(f)
    distro = [row for row in reader]

# chunk distribution list into blocks of 30
chunks = [distro[x:x+30] for x in range(0, len(distro), 30)]

# create outlook instance
outlook = client.Dispatch('Outlook.Application')

# iterate through chunks and send mail
for chunk in chunks:
    # iterate through each recipient in chunk and send mail
    for name, address in chunk:
        message = outlook.CreateItem(0)
        message.To = address
        message.Subject = "Your time entry is past due!"
        message.Body = template.format(name)
        message.Send()

    # wait 60 seconds before sending next chunk
    sleep(60)

Some of the skills that you've learned already are used in this example, such as email templates and chunking a distribution.

Method 2 - Create all, then send (Two Steps)

With this method, all of the emails are created first and then saved in the drafts folder. Then, I search the drafts folder for the emails that I want to send at a rate of 30 per minute by using a timer. This one is a little more complicated, but can be useful if you want to separate the creation and sending stages. Everything else about the email is exactly the same.

import csv
from time import sleep
import win32com.client as client

# open distribution list
with open('people.csv', 'r', newline='') as f:
    reader = csv.reader(f)
    distro = [row for row in reader]

# create outlook instance
outlook = client.Dispatch('Outlook.Application')

# create template for message body
template = "{}, please submit your time as soon as possible!"

# create all messages and save to drafts
for name, email in distro:
    message = outlook.CreateItem(0)
    message.To = email
    message.Subject = "Your time entry is past due!"
    message.Body = template.format(name)
    message.Save()

# extract message from drafts folder (filter only relevant messages)
namespace = outlook.GetNamespace("MAPI")
drafts_folder = namespace.GetDefaultFolder(16)
messages = [item for item in drafts_folder.Items if item.Subject.startswith("Your time entry")]

# chunk messages into blocks of 30
chunks = [messages[x:x+30] for x in range(0, len(messages), 30)]

# send all messages in batches of 30 per minute
for chunk in chunks:
    for message in chunk:
        message.Send()

    # wait 60 seconds for next batch to send
    sleep(60)

This method requires you to iterate through the drafts folder. However, pretty much everything else is familiar from the previous example.