How to send Gmail email with multiple CC:'s - python

I am looking for a quick example on how to send Gmail emails with multiple CC:'s. Could anyone suggest an example snippet?

I've rustled up a bit of code for you that shows how to connect to an SMTP server, construct an email (with a couple of addresses in the Cc field), and send it. Hopefully the liberal application of comments will make it easy to understand.
from smtplib import SMTP_SSL
from email.mime.text import MIMEText
## The SMTP server details
smtp_server = "smtp.gmail.com"
smtp_port = 587
smtp_username = "username"
smtp_password = "password"
## The email details
from_address = "address1#domain.com"
to_address = "address2#domain.com"
cc_addresses = ["address3#domain.com", "address4#domain.com"]
msg_subject = "This is the subject of the email"
msg_body = """
This is some text for the email body.
"""
## Now we make the email
msg = MIMEText(msg_body) # Create a Message object with the body text
# Now add the headers
msg['Subject'] = msg_subject
msg['From'] = from_address
msg['To'] = to_address
msg['Cc'] = ', '.join(cc_addresses) # Comma separate multiple addresses
## Now we can connect to the server and send the email
s = SMTP_SSL(smtp_server, smtp_port) # Set up the connection to the SMTP server
try:
s.set_debuglevel(True) # It's nice to see what's going on
s.ehlo() # identify ourselves, prompting server for supported features
# If we can encrypt this session, do it
if s.has_extn('STARTTLS'):
s.starttls()
s.ehlo() # re-identify ourselves over TLS connection
s.login(smtp_username, smtp_password) # Login
# Send the email. Note we have to give sendmail() the message as a string
# rather than a message object, so we need to do msg.as_string()
s.sendmail(from_address, to_address, msg.as_string())
finally:
s.quit() # Close the connection
Here's the code above on pastie.org for easier reading
Regarding the specific question of multiple Cc addresses, as you can see in the code above, you need to use a comma separated string of email addresses, rather than a list.
If you want names as well as addresses you might as well use the email.utils.formataddr() function to help get them into the right format:
>>> from email.utils import formataddr
>>> addresses = [("John Doe", "john#domain.com"), ("Jane Doe", "jane#domain.com")]
>>> ', '.join([formataddr(address) for address in addresses])
'John Doe <john#domain.com>, Jane Doe <jane#domain.com>'
Hope this helps, let me know if you have any problems.

If you can use a library, I highly suggest http://libgmail.sourceforge.net/, I have used briefly in the past, and it is very easy to use. You must enable IMAP/POP3 in your gmail account in order to use this.
As for a code snippet (I haven't had a chance to try this, I will edit this if I can):
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os
#EDIT THE NEXT TWO LINES
gmail_user = "your_email#gmail.com"
gmail_pwd = "your_password"
def mail(to, subject, text, attach, cc):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject
#THIS IS WHERE YOU PUT IN THE CC EMAILS
msg['Cc'] = cc
msg.attach(MIMEText(text))
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)
mailServer = smtplib.SMTP("smtp.gmail.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user, gmail_pwd)
mailServer.sendmail(gmail_user, to, msg.as_string())
# Should be mailServer.quit(), but that crashes...
mailServer.close()
mail("some.person#some.address.com",
"Hello from python!",
"This is a email sent with python")
For the snippet I modified this

Related

Sending an Email from a python script without a from address

So I have seen lots of great info on here about sending automated emails using python. However, my task is slightly different. The script im working on needs to send an automated email when some condition is true then the email contains the printed output. But since this is for work the file is stored on a shared server and therefore, I cannot be the one to "send" the email, it needs to send automatically from the file. My question is therefore how this email can be sent with no "from" address, or if this is even possible.
Additionally, how can I make sure that the email contains the printed output? Below is the attached code im using. The variables stored in the list are dataframes.
mylist = [right_branchcode, right_branchname, right_sellingcode, right_advcorp, right_childparent, \
right_eliteCategoryId, right_partyid, right_retailmga]
flag = True
for item in mylist:
if len(item) > 0:
print(item)
flag = True
else:
pass
def send_email(audit):
fromaddr = " >"
toaddr = "recip#mail, recip2#mail"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "Alert: Audit Mismatch For DimAdvisor"
body = "Current mismatch in dimAdvisor found on : " + temperature
msg.attach(MIMEText(body, 'plain'))
server = smtplib.SMTP('smtp-mail.outlook.com', 587)
server.starttls()
server.login(fromaddr, "password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
Any help would be great. Thanks!
This is how you can send email using Python:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
recipients = ['john.doe#example.com', 'john.smith#example.co.uk']
msg = MIMEMultipart()
msg['From'] = "Can be any string you want, use ASCII chars only " # sender name
msg['To'] = ", ".join(recipients) # for one recipient just enter a valid email address
msg['Subject'] = "Subject"
body = "message body"
msg.attach(MIMEText(body, 'plain'))
server = smtplib.SMTP('smtp.gmail.com', 587) # put your relevant SMTP here
server.ehlo()
server.starttls()
server.ehlo()
server.login('jhon#gmail.com', '1234567890') # use your real gmail account user name and password
server.send_message(msg)
server.quit()
Please note this line:
msg['From'] = "Can be any string you want, use ASCII chars only " # sender name
You can write any string in the From field regardless of any real email address. I didn't try to leave it empty but I guess you can try it yourself :-)

How to send emails programmatically and hide the sender address?

I would like to send mail notifications to my customers via python. The problem is the sender mail account needs to be hidden. Just to be clear - this is not for phishing or spamming, only personal use!
I used smtplib and setup a new 'noreply' account in gmail, but even when providing an alias to the message, the 'mail from:' header contains my actual mail.
import smtplib
from email.mime.text import MIMEText
from email.utils import *
email_sender = 'noreply%%#gmail.com'
email_receiver = 'example%%%#gmail.com'
subject = 'Python!'
msg = MIMEText('This is the body of the message.')
msg['To'] = formataddr(('Recipient', 'example%%%#gmail.com'))
msg['From'] = formataddr(('Author', 'author#example.com'))
msg['Subject'] = 'Simple test message'
connection = smtplib.SMTP('smtp.gmail.com', 587)
connection.starttls()
connection.login(email_sender, 'password')
connection.sendmail(msg['From'], email_receiver, msg.as_string())
connection.quit()
I get the mail in to my inbox as expected but when clicking 'more details' the original sender address appears.
The first argument to sendmail is the envelope sender, and should be just the email terminus, not a formatted address; so passing in msg['From'] there is doubly wrong (one, because you don't want to show it; and two, because you are passing in the entire From: header with display name and all).

Python 2.7 - I am Using smtplib to send mails to multiple people, but the subject line in email sent is not reflecting in every mail

I am using smtplib to send mails to multiple users, I am reading email ids from mail.txt , and names of receivers from names.txt file and subject from subject.txt file,
Somehow the subject is not reflecting in all emails, only last mail that is sent has subject and others don't. But when I print the subject in each iteration it prints, I am not sure why this is happening. I tried to change number of receipts and checked, but the issue doesn't solve. Also I tried to keep the import statements outside the loop as well.
Can you please help me with this code.
Code :
ob1 = open("names.txt","r")
fname = ob1.readlines()
ob1.close()
ob2 = open("mail.txt","r")
email = ob2.readlines()
ob2.close()
ob3 = open("subject.txt","r")
aname = ob3.readlines()
ob3.close()
for i in range(len(fname)):
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
msg = MIMEMultipart()
msg['From'] = 'my_email_id'
msg['To'] = email[i]
msg['Subject'] = aname[i]
message = 'some mail text'
msg.attach(MIMEText(message))
mailserver = smtplib.SMTP('smtp.gmail.com',587)
mailserver.ehlo()
mailserver.starttls()
mailserver.ehlo()
mailserver.login('my_email_id', '******')
mailserver.sendmail('my_email_id',email[i],msg.as_string())
mailserver.quit()

Python smtplib: only the first email out of several arrives to destination

I have put together a function send_email [1] to send emails with support for plain-text and html messages. It works well, but I have an issue I don't quite know how to debug. My system has sendmail as its MTA.
The function is called in a for loop, as follows:
for data in data_set:
subject, message = process(data) # Irrelevant stuff
send_email(subject, message, "fixed#email.address")
In the debug output of smtplib [1] I see that all calls to send_email completed successfully. The weird behavior is:
If the message is "short" (I tested with a single line), all sent messages actually arrive to fixed#email.address
If the message is "not short" (that is, the multiple lines I generate with the real process_data function), only the first email does arrive, while the others don't, even though the debug output of smtplib in [1] reports success for each and all of the emails.
If the message is equally "not short" but the destination address is different for each message, then all messages arrive to their intended destinations.
For the latter case, the for loop would look like:
addresses = ["fixed#email.address", "fixed.2#email.address", ...]
for data, addr in zip(data_set, addresses):
subject, message = process(data) # Irrelevant stuff
send_email(subject, message, addr)
The intended behavior is of course different addresses for different data, but I'm concerned that not understanding why this happens might bite me in an unexpected way later on.
[1] My send mail function:
import smtplib
import socket
import getpass
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def send_email (subject, message, to, reply_to='', cc='', html_message=''):
COMMASPACE = ", "
user, host = get_user_and_host_names()
sender = '%s#%s' % (user, host)
receivers = make_address_list(to)
copies = make_address_list(cc)
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = COMMASPACE.join(receivers)
if reply_to:
msg.add_header('Reply-to', reply_to)
if len(copies):
msg.add_header('CC', COMMASPACE.join(copies))
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
if message:
msg.attach( MIMEText(message, 'plain'))
if html_message:
msg.attach( MIMEText(html_message, 'html'))
smtpObj = smtplib.SMTP('localhost')
smtpObj.set_debuglevel(1)
smtpObj.sendmail(sender, receivers, msg.as_string())
smtpObj.quit()
print "\nSuccessfully sent email to:", COMMASPACE.join(receivers)
def get_user_and_host_names():
user = getpass.getuser()
host = socket.gethostname()
return user, host
def make_address_list (addresses):
if isinstance(addresses, str):
receivers = addresses.replace(' ','').split(',')
elif isinstance(addresses, list):
receivers = addresses
return receivers
A working solution I had for sending email:
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import smtplib
class EMail(object):
""" Class defines method to send email
"""
def __init__(self, mailFrom, server, usrname, password, files, debug=False):
self.debug = debug
self.mailFrom = mailFrom
self.smtpserver = server
self.EMAIL_PORT = 587
self.usrname = usrname
self.password = password
def sendMessage(self, subject, msgContent, files, mailto):
""" Send the email message
Args:
subject(string): subject for the email
msgContent(string): email message Content
files(List): list of files to be attached
mailto(string): email address to be sent to
"""
msg = self.prepareMail(subject, msgContent, files, mailto)
# connect to server and send email
server=smtplib.SMTP(self.smtpserver, port=self.EMAIL_PORT)
server.ehlo()
# use encrypted SSL mode
server.starttls()
# to make starttls work
server.ehlo()
server.login(self.usrname, self.password)
server.set_debuglevel(self.debug)
try:
failed = server.sendmail(self.mailFrom, mailto, msg.as_string())
except Exception as er:
print er
finally:
server.quit()
def prepareMail(self, subject, msgHTML, attachments, mailto):
""" Prepare the email to send
Args:
subject(string): subject of the email.
msgHTML(string): HTML formatted email message Content.
attachments(List): list of file paths to be attached with email.
"""
msg = MIMEMultipart()
msg['From'] = self.mailFrom
msg['To'] = mailto
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
#the Body message
msg.attach(MIMEText(msgHTML, 'html'))
msg.attach(MIMEText("Add signature here"))
if attachments:
for phile in attachments:
# we could check for MIMETypes here
part = MIMEBase('application',"octet-stream")
part.set_payload(open(phile, "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(phile))
msg.attach(part)
return msg
I hope this helps.
My Working solution to format your list in this manner (after many hours of experiment):
["firstemail#mail.com", "secondmail#mail.com", "thirdmail#email.com"]
I used:
to_address = list(str(self.to_address_list).split(","))
to convert my QString into string then into list with splitting with a ","
In my case COMMASPACE was not working, because on splitting a space was already added by default.

Send an email having an attachment for multiple addresses in python

I wrote the below code for sending an email to multiple addresses.... But i am able to send the mail for only first address in the list...could give me exact reason and solution for it. Thanks in advance!!
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from smtplib import SMTP
COMMASPACE = ', '
msg = MIMEMultipart()
msg['Subject'] = 'Test attaching mail'
msg['From'] = 'x#x.com'
msg['Reply-to'] = ''
msg['To'] = COMMASPACE.join(['x1#x.com','x2#x.com','x3#x.com'])
# That is what u see if dont have an email reader:
msg.preamble = 'Multipart massage.\n'
# This is the textual part:
part = MIMEText("Hello im sending an email from a python program")
msg.attach(part)
# This is the binary part(The Attachment):
file="../logs_usecase/TestUsecase.log"
part = MIMEApplication(open(file,"rb").read())
part.add_header('Content-Disposition', 'attachment', filename=file)
msg.attach(part)
# Create an instance in SMTP server
smtp = SMTP("smtp.gmail.com:587")
# Start the server:
smtp.starttls()
smtp.ehlo()
smtp.login('x#x.com', "xxxxx")
# Send the email
smtp.sendmail(msg['From'], msg['To'], msg.as_string())
SMTP.sendmail expects a list of recipients, but you're passing a string with concatenated email addresses:
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
Send mail. The required arguments are an RFC 822 from-address string, a list of RFC 822 to-address strings (a bare string will be treated as a list with 1 address), and a message string.
(emphasis added)
You should pass the same list you join with COMMASPACE directly to SMTP.sendmail instead of passing the concatenated flat string.

Categories