Wisam Ahmed
Wisam Ahmed

Reputation: 155

Updating "To:" Email-Header in a while loop in python

Below is a code to send multiple emails to contacts loaded from a text file.

import time
    from time import sleep

    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    import smtplib

    uname = #[email protected]
    name = "KTester"
    password = #password1
    server = smtplib.SMTP('smtp.gmail.com: 587')
    server.starttls()
    server.login(uname, password)
    message="Test"

    msg = MIMEMultipart('Alternative')
    f= open("list.txt","r")clear

    if f.mode == "r":
      cont = f.read().splitlines()
      for x in cont:
        print time.ctime()

        msg['Subject'] = "Test Mail - cripted Sample"
        msg['To'] = x
        msg['From'] = name+"\x0A\x0D"+uname
        msg.attach(MIMEText(message, 'html'))

        print "successfully sent email to %s:" % (msg['To'])

    f.close()
    server.quit()

OUTPUT: enter image description here

In this case, the first compilation is the expected outcome, which we can get if we use print "successfully sent email to %s:" % (x)

The Variable 'x' changes its value at the end of each iteration.

However, msg['To'] = x does not accept value from second iteration of the loop(The second code run above).

Assignment operation does not work on the message object.

Kindly help with whats going wrong. Thanks!

Upvotes: 2

Views: 1470

Answers (3)

snakecharmerb
snakecharmerb

Reputation: 55799

This behaviour is by design.

Reassigning to msg['to'] doesn't overwrite the existing mail header, it adds another. To send the existing message to a new address you need to delete the 'to' header before setting it.

del msg['to']
msg['to'] = '[email protected]'

This applies to other headers too. From the docs for Message.__setitem__:

Note that this does not overwrite or delete any existing header with the same name. If you want to ensure that the new header is the only one present in the message with field name name, delete the field first, e.g.:

del msg['subject']

msg['subject'] = 'Python roolz!'

Upvotes: 2

Ghantey
Ghantey

Reputation: 636

The main problem in your script is that you have defined msg = MIMEMultipart('Alternative') outside for loop. Try defining msg = MIMEMultipart('Alternative') inside for loop.

The solution is same as given by @Daniel Sims but I have turned your script more readable so that everyone can understand

I have edited your code in my own way which worked like a charm for me. Have a try:

[CODE]

import time
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

# credentials    
uname = 'your email address'
name = "KTester"
password = 'password'

# Connecting to gmail server and logging to your gmail account
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
server.login(uname, password)

message = "Test"  # Your message

with open('list.txt', 'r') as lst:
    lines = lst.readlines()  # Reading files to get emails

    for line in lines:  # Getting each email from list of emails
        msg = MIMEMultipart('Alternative')   # This line is added here(which if you have did outside of the for loop)
        msg['Subject'] = "Test Mail - cripted Sample"
        msg['To'] = line
        msg['From'] = '{}{}{}'.format(name, "\x0A\x0D", uname)
        msg.attach(MIMEText(message, 'html'))

        print(time.ctime())
        print("successfully sent email to {}".format(msg['To']))

 server.quit()

Upvotes: 0

MonteCarloSims
MonteCarloSims

Reputation: 1771

(Edit of original answer, after clarification of question's output)

Try moving the following line into the for loop:

msg = MIMEMultipart('Alternative')

To look like this:

for x in cont:
    msg = MIMEMultipart('Alternative')
    print time.ctime()

    msg['Subject'] = "Test Mail - cripted Sample"
    msg['To'] = x
    msg['From'] = name+"\x0A\x0D"+uname
    msg.attach(MIMEText(message, 'html'))

    print "successfully sent email to %s:" % (msg['To'])

I think the msg needs to be new in each iteration.

My testing yielded exactly the same results - appearing to send to the same email address over and over. Because the msg headers simply get appended to. The for loop was creating multiple to: headers, but printing was only revealing the first. See below for what it looks like in debug:

Header of To: line in original for loop

Output of original for loop

After adding the msg instantiation to within the for loop, the output was as expected with different names each iteration.

I think the root of how msg is structured might be that email can have more than one person on the to: line. The above solution presumes that you only wanted one person on each to: line.

Upvotes: 0

Related Questions