1

I have a python array with 3 email addresses:

email_group = df.EMAIL.unique()

test@test.com
test1@test.com
test2@test.com

How do I loop through the array of emails, assign the first email address to the "mail.To" field and send? Then loop to the 2nd email address and send, and finally sending a 3rd email with the final address in the array.

End result: I need one email sent to each address in the array using a loop.

outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = 'POPULATED FROM ARRAY LOOP'
mail.Subject = 'Report'
mail.Body = """Report is attached."""
mail.Send()
Aviv Yaniv
  • 6,188
  • 3
  • 7
  • 22
Mark
  • 177
  • 3
  • 12

2 Answers2

2

Option 1 : Using a class

email_addresses = ['test@test.com', 'test1@test.com', 'test2@test.com']


class EmailsSender:
    def __init__(self):
        self.outlook = win32.Dispatch('outlook.application')

    def send_email(self, to_email_address, attachment_path):
        mail = self.outlook.CreateItem(0)
        mail.To = to_email_address
        mail.Subject = 'Report'
        mail.Body = """Report is attached."""
        if attachment_path:
            mail.Attachments.Add(Source=attachment_path, Type=olByValue)
        mail.Send()

    def send_emails(self, email_addresses, attachment_path=None):
        for email in email_addresses:
            self.send_email(email, attachment_path)

attachment_path = 'Enter report path here'
email_sender = EmailsSender()
email_sender.send_emails(email_addresses, attachment_path)

Option 2 :Using a function

outlook = win32.Dispatch('outlook.application')

def send_email(outlook, to_email_address, attachment_path):
    mail = outlook.CreateItem(0)
    mail.To = to_email_address
    mail.Subject = 'Report'
    mail.Body = """Report is attached."""
    if attachment_path:
        mail.Attachments.Add(Source=attachment_path, Type=olByValue)
    mail.Send()

attachment_path = 'Enter report path here'
for email in email_addresses:
    send_email(outlook, email_addresses)

Option 3 : Just It

email_addresses = ['test@test.com', 'test1@test.com', 'test2@test.com']

outlook = win32.Dispatch('outlook.application')

attachment_path = 'Enter report path here'

for email in email_addresses:
    mail = outlook.CreateItem(0)
    mail.To = email
    mail.Subject = 'Report'
    mail.Body = """Report is attached."""
    mail.Attachments.Add(Source=attachment_path, Type=olByValue)
    mail.Send()
Aviv Yaniv
  • 6,188
  • 3
  • 7
  • 22
  • If I wanted to attach a specific excel file to each email, could I use similar logic to pull the attachment from the folder location? – Mark Aug 26 '20 at 18:57
  • 1
    Dear @Mark, Thank you for asking. The class and method are different in that matter that they are easier to activate "Launch & Forget": all you care about is passing the email address (and - the file if you want, as a parameter). They hold the sending logic together, separated from where you activate it, so code is easier for maintenance (if you actually use that code, its important, AND going to be more important as you use it more). However - all options - are functionally equivalent. Hope it helped :) – Aviv Yaniv Aug 26 '20 at 19:02
  • 1
    @Mark Honestly, I haven't been familiar with outlook sending in Python. However, researched it for you, added and edited for each of the options this capability. – Aviv Yaniv Aug 26 '20 at 19:15
  • I really appreciate that @Aviv! One question regarding the attachments piece, does the code you provided look through the attachmen_path and attach everything in the folder, just the first, or loop through and attach a 1:1 to each email that is sent? Did that question make any sense? – Mark Aug 26 '20 at 19:28
  • 1
    The code takes the file that it's path is given. To loop for files in directory look [Find all files in a directory with extension .txt in Python](https://stackoverflow.com/questions/3964681/find-all-files-in-a-directory-with-extension-txt-in-python) – Aviv Yaniv Aug 26 '20 at 19:30
  • I use the following piece of code to find the most recent file in a folder location and use that as the attachment. But how would I change the code to do a 1:1 with the email addresses in your class example above? list_of_files1 = glob.glob(r'C:\Users\OneDrive\*.xlsx') latest_file1 = max(list_of_files1, key=os.path.getctime) attachment = latest_file1 mail.Attachments.Add(attachment) – Mark Aug 26 '20 at 19:35
  • I don't really understand you. – Aviv Yaniv Aug 26 '20 at 19:35
  • I want to send 1 email with the first file in the attachment folder, then a 2nd email with the 2nd file in the attachment folder and finally the 3rd email with the 3rd file in the attachment folder. – Mark Aug 26 '20 at 19:38
  • 1
    How would you determine the order of the files? and how would you match the files to the emails? Please open a new question with more details! – Aviv Yaniv Aug 26 '20 at 19:41
  • olByValue had me searching Google, info here: https://learn.microsoft.com/en-us/office/vba/api/outlook.olattachmenttype – Graham Monkman Jan 25 '22 at 11:40
  • Hi @ Aviv Yaniv, can you please answer below question https://stackoverflow.com/questions/76513447/once-python-script-run-completed-how-to-send-created-log-files-results-to-outloo/76514362#76514362 – lAkShMipythonlearner Jun 21 '23 at 08:40
0

If I understand your question, you can simply use a for loop over your list of addresses

emails = ['test@test.com', 'test1@test.com', 'test2@test.com']
outlook = win32.Dispatch('outlook.application')

for email in emails:
    mail = outlook.CreateItem(0)
    mail.To = email 
    mail.Subject = 'Report'
    mail.Body = """Report is attached."""
    mail.Send()
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • This looks like an option that will work. If I wanted to attach a specific excel file to each email, could I use similar logic to pull the attachment from the folder location? – Mark Aug 26 '20 at 18:56