I'm using the code described in:
Sending email via gmail & python
to send e-mails. Everything works great. Now I'd like to add a Bcc (one or more) and I don't know how.
If I add: message['Bcc'] = 'mail#mail.com' it works but the senders see the Bcc, and I don't want that.
I know that using SMTP you can:
smtp = smtplib.SMTP('smtp.gmail.com', 587)
smtp.sendmail(user, [to] + bcc, message.as_string())
but I don't want to do it that way.
How can I add Bcc without the sender knowing about it, using google google_auth_oauthlib?
This is the code I'm using
import httplib2
import os
import oauth2client
from oauth2client import client, tools, file
import base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from apiclient import errors, discovery
import mimetypes
from email.mime.image import MIMEImage
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
SCOPES = 'https://www.googleapis.com/auth/gmail.send'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Gmail API Python Send Email'
def get_credentials():
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'gmail-python-email-send.json')
store = oauth2client.file.Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
credentials = tools.run_flow(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def SendMessage(sender, to, subject, msgHtml, msgPlain, attachmentFile=None):
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
if attachmentFile:
message1 = createMessageWithAttachment(sender, to, subject, msgHtml, msgPlain, attachmentFile)
else:
message1 = CreateMessageHtml(sender, to, subject, msgHtml, msgPlain)
result = SendMessageInternal(service, "me", message1)
return result
def SendMessageInternal(service, user_id, message):
try:
message = (service.users().messages().send(userId=user_id, body=message).execute())
print('Message Id: %s' % message['id'])
return message
except errors.HttpError as error:
print('An error occurred: %s' % error)
return "Error"
return "OK"
def CreateMessageHtml(sender, to, subject, msgHtml, msgPlain):
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = to
msg.attach(MIMEText(msgPlain, 'plain'))
msg.attach(MIMEText(msgHtml, 'html'))
return {'raw': base64.urlsafe_b64encode(msg.as_string())}
def createMessageWithAttachment(
sender, to, subject, msgHtml, msgPlain, attachmentFile):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
msgHtml: Html message to be sent
msgPlain: Alternative plain text message for older email clients
attachmentFile: The path to the file to be attached.
Returns:
An object containing a base64url encoded email object.
"""
message = MIMEMultipart('mixed')
message['to'] = to
message['from'] = sender
message['subject'] = subject
messageA = MIMEMultipart('alternative')
messageR = MIMEMultipart('related')
messageR.attach(MIMEText(msgHtml, 'html'))
messageA.attach(MIMEText(msgPlain, 'plain'))
messageA.attach(messageR)
message.attach(messageA)
print("create_message_with_attachment: file: %s" % attachmentFile)
content_type, encoding = mimetypes.guess_type(attachmentFile)
if content_type is None or encoding is not None:
content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1)
if main_type == 'text':
fp = open(attachmentFile, 'rb')
msg = MIMEText(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'image':
fp = open(attachmentFile, 'rb')
msg = MIMEImage(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'audio':
fp = open(attachmentFile, 'rb')
msg = MIMEAudio(fp.read(), _subtype=sub_type)
fp.close()
else:
fp = open(attachmentFile, 'rb')
msg = MIMEBase(main_type, sub_type)
msg.set_payload(fp.read())
fp.close()
filename = os.path.basename(attachmentFile)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
message.attach(msg)
return {'raw': base64.urlsafe_b64encode(message.as_string())}
def main():
to = "to#address.com"
sender = "from#address.com"
subject = "subject"
msgHtml = "Hi<br/>Html Email"
msgPlain = "Hi\nPlain Email"
SendMessage(sender, to, subject, msgHtml, msgPlain)
# Send message with attachment:
SendMessage(sender, to, subject, msgHtml, msgPlain, '/path/to/file.pdf')
if __name__ == '__main__':
main()
Related
I would like to send two file attachments by email but I do not know how to do, any help?
def sendmail():
sender_email = "sender#gmail.com"
receiver_email = "receiver#gmail.com"
message = MIMEMultipart()
message["From"] = sender_email
message['To'] = receiver_email
message['Subject'] = "Deine Monatseinteilung"
file = (f'{myPath}/File-2-2022.ics')
attachment = open(file,'rb')
obj = MIMEBase('application','octet-stream')
obj.set_payload((attachment).read())
encoders.encode_base64(obj)
obj.add_header('Content-Disposition',"attachment; filename= "+file)
message.attach(obj)
my_message = message.as_string()
email_session = smtplib.SMTP('smtp.gmail.com',587)
email_session.starttls()
email_session.login(sender_email,'xxxxxx')
email_session.sendmail(sender_email,receiver_email,my_message)
email_session.quit()
print(f"Deine monatseinteilung wurde an deine E-Mail-Adresse gesendet ({receiver_email})")
sendmail()
Try using this code snippet below:
import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
def _send_email(send_from, send_to, subject, text, files=None):
assert isinstance(send_to, list)
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(text))
for f in files or []:
with open(f, "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(f)
)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
smtp = smtplib.SMTP(SERVER, PORT)
smtp.login(USER, PASS)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
Then you can call the function like so:
send_from = "fakeemail3#domain.com"
send_to = ['fakeemail1#domain.com', 'fakeemail2#domain.com']
subject = "My Subject"
text = "This is a email."
files = ["pathtofile1", "pathtofile2"]
_send_email(send_from, send_to, subject, text, files)
Is it possible to send automated email messages with Amazon Workmail through a Python script?
My code keeps hanging and when I can the run I get a SMTP server connection error. How can I fix this? I presume, its the SMTP configuration, but does anyone know what that is?
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import os.path
import csv
from random import randint
from time import sleep
def send_email(email_recipient,
email_subject,
email_message,
attachment_location=''):
email_mime_sender = 'xxxxx <xxxxx#yyyyyy.co.uk>'
email_sender = 'xxxxx'
email_password = 'xxxxx'
msg = MIMEMultipart()
msg['From'] = email_mime_sender
msg['To'] = email_recipient
msg['Subject'] = email_subject
msg.attach(MIMEText(email_message, 'plain'))
if attachment_location != '':
filename = os.path.basename(attachment_location)
attachment = open(attachment_location, "rb")
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',
"attachment; filename= %s" % filename)
msg.attach(part)
try:
server = smtplib.SMTP_SSL('smtp.mail.eu-west-1.awsapps.com', 465)
server.ehlo()
server.starttls()
server.login(email_sender, email_password)
text = msg.as_string()
server.sendmail(email_sender, email_recipient, text)
print('Email sent to %s' % email_recipient)
server.quit()
except:
print("SMTP server connection error")
return True
def main():
file = 'test.csv'
with open(file, "rb") as f:
next(f)
for line in f:
line = line.replace("\n", "")
line = line.replace("\r", "")
split_line = line.split(",")
email_subject = 'Can I ask you a few questions?'
raw_email_message = [
'Test',
'Test'
]
email_message = '\n\n'.join(raw_email_message)
send_email(split_line[1], email_subject, email_message, '')
sleep(randint(1, 3))
main()
Removing server.starttls() from the this block fixed it:
try:
server = smtplib.SMTP_SSL('smtp.mail.eu-west-1.awsapps.com', 465)
server.ehlo()
server.login(email_user, email_password)
text = msg.as_string()
server.sendmail(email_sender, email_recipient, text)
print('Email sent to %s' % email_recipient)
server.quit()
except Exception as e:
print(e)
print("SMTP server connection error")
return True
import smtplib
import mechanize
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
def sem():
if not os.path.isfile('key.txt'):
print('below details are req to send report')
gmail_user = input('enter your email=')
gmail_app_password = input('enter your email password=')
print('pls accept the login in your gmail account ')
ke = open('key.txt',mode="w+")
ke.write(gmail_user)
ke.write(':')
ke.write(gmail_app_password)
ke.close()
if not os.path.isfile('sto.txt'):
gmai = input('enter the email to send report=')
ke = open('sto.txt',mode="w+")
ke.write(gmai)
ke.close()
with open('key.txt',mode="r")as f:
ds=f.readlines()
d=''.join(ds)
r=d.split(':')
with open('sto.txt',mode="r")as f:
ds=f.readlines()
f=ds
print(f)
gmail_user = r[0]
gmail_app_password = r[1]
sent_from = gmail_user
sent_to = ds
sent_subject = "hey amo lio ,how are ?"
sent_body = ("Hey, what's up? friend!")
email_text = """\
To: %s
Subject: %s
%s
""" % (", ".join(sent_to), sent_subject, sent_body)
mail = MIMEMultipart()
mail["Subject"] = sent_subject
mail["From"] = sent_from
mail["To"] = sent_to
mail.attach[MIMEText(sent_body,'html')]
ctype, encoding = mimetypes.guess_type(_file)
maintype, subtype = ctype.split('/', 1)
fp = open("./data/mood.txt")
msg = MIMEText(fp.read(), _subtype=subtype)
fp.close()
filename = os.path.basename(_file)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
mail.attach(msg)
print('done')
server.sendmail(sent_from, sent_to, mail.as_string())
try:
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.ehlo()
server.login(gmail_user, gmail_app_password)
server.sendmail(sent_from, sent_to, email_text)
server.close()
print('Email sent!')
except Exception as exception:
print("Error: %s!\n\n" % exception)
sem()
How can I attach the helloword.txt file in this email? This code is working fine, I just want to send an attachment along with it. This code lets me me send the body without any attachment. Also, how do I encrypt the key.txt file which store email address and password, and to send email it it requires the password to be entered (diff pass)?
You need to use the 'MIMEMultipart' module to attach files.
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
mail = MIMEMultipart()
mail["Subject"] = sent_subject
mail["From"] = sent_from
mail["To"] = sent_to
mail.attach(MIMEText(sent_body,'html'))
ctype, encoding = mimetypes.guess_type(_file)
maintype, subtype = ctype.split('/', 1)
fp = open("/path/to/attachment/file.txt")
# If file mimetype is video/audio use respective email.mime module.
# Here assuming 'maintype' == 'text' we will use MIMEText
msg = MIMEText(fp.read(), _subtype=subtype)
fp.close()
filename = os.path.basename(_file)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
mail.attach(msg)
server.sendmail(sent_from, sent_to, mail.as_string())
import smtplib
import mechanize
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import mimetypes
import pdb
def email:
sender_address = gmail_user
#make it input
receiver_address = gmail_user
#Setup the MIME
fromaddr = gmail_user
sendto = gmail_app_password
sender_pass = gmail_app_password = input('enter your email password')
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = sendto
msg['Subject'] = 'This is cool'
body = "this is the body of the text message"
msg.attach(MIMEText(body, 'plain'))
filename = 'mood.txt'
attachment = open('./data/mood.txt', 'rb')
part = MIMEBase('application', "octet-stream")
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename= %s' % filename)
msg.attach(part)
smtpObj = smtplib.SMTP('smtp.gmail.com', 587)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login(gmail_user, gmail_app_password)
text = msg.as_string()
smtpObj.sendmail(fromaddr, sendto , text)
smtpObj.quit() # attach the instance 'p' to instance 'msg'
here is perfect working code for sending email
I need to send multiple emails (like 200 customized emails each day), but all have same pdf attachment. Is it possible to upload the attachment only once to save on upload time?
Even better than that, is it possible to upload the file only once on a google server and each day just reference that file?
Just for reference here is the code (modified a bit from google developer sample code):
# main function
def SendMessageAttachment(sender, to, subject, msgHtml, msgPlain, attachmentFile):
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
message1 = create_message_with_attachment(sender, to, subject, msgPlain, attachmentFile)
SendMessageInternal(service, "me", message1)
def SendMessageInternal(service, user_id, message):
try:
message = (service.users().messages().send(userId=user_id, body=message).execute())
print 'Message Id: %s' % message['id']
return message
except errors.HttpError, error:
print 'An error occurred: %s' % error
def create_message_with_attachment(
sender, to, subject, message_text, attachmentFile):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
file: The path to the file to be attached.
Returns:
An object containing a base64url encoded email object.
"""
message = MIMEMultipart()
message['to'] = to
message['from'] = sender
message['subject'] = subject
msg = MIMEText(message_text)
message.attach(msg)
print "create_message_with_attachment: file:", attachmentFile
content_type, encoding = mimetypes.guess_type(attachmentFile)
if content_type is None or encoding is not None:
content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1)
if main_type == 'text':
fp = open(attachmentFile, 'rb')
msg = MIMEText(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'image':
fp = open(attachmentFile, 'rb')
msg = MIMEImage(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'audio':
fp = open(attachmentFile, 'rb')
msg = MIMEAudio(fp.read(), _subtype=sub_type)
fp.close()
else:
fp = open(attachmentFile, 'rb')
msg = MIMEBase(main_type, sub_type)
msg.set_payload(fp.read())
fp.close()
filename = os.path.basename(attachmentFile)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
message.attach(msg)
return {'raw': base64.urlsafe_b64encode(message.as_string())}
the attachment is loaded here:
part = MIMEApplication(open("mypdf.pdf","rb").read())
but the reference for the header can be anywhere
part.add_header('Content-Disposition', 'attachment', filename="file.pdf")
msg.attach(part)
You could write a function to add this header before sending the mail and iterate over all your recipients.
I'm trying to email multiple recipients using the pyton script below. I've searched the forum for answers, but have not been able to implement any of them correctly. If anyone has a moment to review my script and spot/resolve the problem it would be greatly appreciated.
Here's my script, I gather my issue is in the 'sendmail' portion, but can't figure out how to fix it:
gmail_user = "sender#email.com"
gmail_pwd = "sender_password"
recipients = ['recipient1#email.com','recipient2#email.com']
def mail(to, subject, text, attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = ", ".join(recipients)
msg['Subject'] = subject
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())
mailServer.close()
mail("recipient1#email.com, recipient2#email.com",
"Subject",
"Message",
"attchachment")
Any insight would be greatly appreciated.
Best,
Matt
It should be more like
mail(["recipient1#email.com", "recipient2#email.com"],
"Subject",
"Message",
"attchachment")
You already have a array of recipients declared,that too globally,You can use that without passing it as an argument to mail.
I wrote this bit of code to do exactly what you want. If you find a bug let me know (I've tested it and it works):
import email as em
import smtplib as smtp
import os
ENDPOINTS = {KEY: 'value#domain.com'}
class BoxWriter(object):
def __init__(self):
pass
def dispatch(self, files, box_target, additional_targets=None, email_subject=None, body='New figures'):
"""
Send an email to multiple recipients
:param files: list of files to send--requires full path
:param box_target: Relevant entry ENDPOINTS dict
:param additional_targets: other addresses to send the same email
:param email_subject: optional title for email
"""
destination = ENDPOINTS.get(box_target, None)
if destination is None:
raise Exception('Target folder on Box does not exist')
recipients = [destination]
if additional_targets is not None:
recipients.extend(additional_targets)
subject = 'Updating files'
if email_subject is not None:
subject = email_subject
message = em.MIMEMultipart.MIMEMultipart()
message['From'] = 'user#domain.com'
message['To'] = ', '.join(recipients)
message['Date'] = em.Utils.formatdate(localtime=True)
message['Subject'] = subject
message.attach(em.MIMEText.MIMEText(body + '\n' +'Contents: \n{0}'.format('\n'.join(files))))
for f in files:
base = em.MIMEBase.MIMEBase('application', "octet-stream")
base.set_payload(open(f, 'rb').read())
em.Encoders.encode_base64(base)
base.add_header('Content-Disposition', 'attachment; filename={0}'.format(os.path.basename(f)))
message.attach(base)
conn = smtp.SMTP('smtp.gmail.com', 587)
un = 'user#gmail.com'
pw = 'test1234'
conn.starttls()
conn.login(un, pw)
conn.sendmail('user#domain.com', recipients, message.as_string())
conn.close()
I was facing the same issue, I fixed this issue now. Here is my code -
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import datetime
def sendMail():
message = MIMEMultipart()
message["To"] = "xxxxx#xxxx.com,yyyy#yyyy.com"
message["Cc"] = "zzzzzz#gmail.com,*********#gmail.com"
message["From"] = "xxxxxxxx#gmail.com"
message["Password"] = "***************"
server = 'smtp.gmail.com:587'
try:
now = datetime.datetime.now()
message['Subject'] = "cxxdRL Table status (Super Important Message) - "+str(now)
server = smtplib.SMTP(server)
server.ehlo()
server.starttls()
server.login(message["From"], message["Password"])
server.sendmail(message["From"], message["To"].split(",") + message["Cc"].split(","), message.as_string())
server.quit()
print('Mail sent')
except:
print('Something went wrong...')
sendMail()