Forwarding an email with python smtplib

19,988

Solution 1

I think the part you had wrong was how to replace the headers in the message, and the fact that you don't need to make a copy of the message, you can just operate directly on it after creating it from the raw data you fetched from the IMAP server.

You did omit some detail so here's my complete solution with all details spelled out. Note that I'm putting the SMTP connection in STARTTLS mode since I need that and note that I've separated the IMAP phase and the SMTP phase from each other. Maybe you thought that altering the message would somehow alter it on the IMAP server? If you did, this should show you clearly that that doesn't happen.

import smtplib, imaplib, email

imap_host = "mail.example.com"
smtp_host = "mail.example.com"
smtp_port = 587
user = "xyz"
passwd = "xyz"
msgid = 7
from_addr = "[email protected]"
to_addr = "[email protected]"

# open IMAP connection and fetch message with id msgid
# store message data in email_data
client = imaplib.IMAP4(imap_host)
client.login(user, passwd)
client.select('INBOX')
status, data = client.fetch(msgid, "(RFC822)")
email_data = data[0][1]
client.close()
client.logout()

# create a Message instance from the email data
message = email.message_from_string(email_data)

# replace headers (could do other processing here)
message.replace_header("From", from_addr)
message.replace_header("To", to_addr)

# open authenticated SMTP connection and send message with
# specified envelope from and to addresses
smtp = smtplib.SMTP(smtp_host, smtp_port)
smtp.starttls()
smtp.login(user, passwd)
smtp.sendmail(from_addr, to_addr, message.as_string())
smtp.quit()

Hope this helps even if this answer comes quite late.

Solution 2

In one application I download messages via POP3 (using poplib) and forward them using your second method... That is, I alter To/From on the original Message and send it, and it works.
Have you tried poking inside smtp.sendmail to see where it stops?

Share:
19,988
robbles
Author by

robbles

Updated on June 05, 2022

Comments

  • robbles
    robbles almost 2 years

    I'm trying to put together a script that automatically forwards certain emails that match a specific criteria to another email.

    I've got the downloading and parsing of messages using imaplib and email working, but I can't figure out how to forward an entire email to another address. Do I need to build a new message from scratch, or can I somehow modify the old one and re-send it?

    Here's what I have so far (client is an imaplib.IMAP4 connection, and id is a message ID):

    import smtplib, imaplib
    
    smtp = smtplib.SMTP(host, smtp_port)
    smtp.login(user, passw)
    
    client = imaplib.IMAP4(host)
    client.login(user, passw)
    client.select('INBOX')
    
    status, data = client.fetch(id, '(RFC822)')
    email_body = data[0][1]
    mail = email.message_from_string(email_body)
    
    # ...Process message...
    
    # This doesn't work
    forward = email.message.Message()
    forward.set_payload(mail.get_payload())
    forward['From'] = '[email protected]'
    forward['To'] = '[email protected]'
    
    smtp.sendmail(user, ['[email protected]'], forward.as_string())
    

    I'm sure there's something slightly more complicated I need to be doing with regard to the MIME content of the message. Surely there's some simple way of just forwarding the entire message though?

    # This doesn't work either, it just freezes...?
    mail['From'] = '[email protected]'
    mail['To'] = '[email protected]'
    smtp.sendmail(user, ['[email protected]'], mail.as_string())
    
  • Damian Moore
    Damian Moore about 3 years
    Small adjustment I needed for Python 3. Binary data from IMAP fetch needs to be decoded, i.e. data[0][1].decode('utf-8').
  • Aemmel
    Aemmel almost 2 years
    @DamianMoore You don't need to decode it in this case. The email module has a function email.message_from_bytes() which is probably safer.