I want to send a .txt file attached to the mail in Python.
Currently the mail is received but without any attachment.
Code bellow
I've sent emails in PHP but Python is completely new to me
The code doesn't return any errors, it simply doesn't send the attachment with the email
with smtplib.SMTP('smtp.gmail.com', 587) as smtp:
server = smtplib.SMTP('smtp.gmail.com', 587)
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
msg = MIMEMultipart()
smtp.login(EMAIL_ADRESS, EMAIL_PASSWORD)
subject = 'Log Register'
filename = 'logs-to-h4wtsh0wt.txt'
attachment = open(filename, 'rb')
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= "+filename)
msg.attach(part)
msg = f'Subject: {subject}\n\n{Body}'
smtp.sendmail(EMAIL_ADRESS,EMAIL_ADRESS, msg)
snakecharmerb is right. You are indeed overriding the message object and therefore losing everything you add before that point.
You can instead set the subject like this:
msg['Subject'] = "Subject of the Mail"
# string to store the body of the mail
body = "Body_of_the_mail"
# attach the body with the msg instance
msg.attach(MIMEText(body, 'plain'))
Because you are attaching a file you will also need to convert the multipart message into a string before sending:
text = msg.as_string()
smtp.sendmail(fromaddr, toaddr, text)
When you created msg with MIMEMultipart() it generated the message object structure for you as per RFC2822 which also gives you FROM, TO, etc.
The msg object also has a bunch of functions you can run outlined in its docs
Related
I am trying to automate some email sending with python and the smtplib library. Currently, it sends the email fine and attaches the file, but the file does not keep the name that I set.
#The body and the attachments for the mail
message.attach(MIMEText(mail_content, 'plain'))
attach_file_name = 'temp.txt'
attach_file = open(attach_file_name, 'rb') # Open the file as binary mode
payload = MIMEBase('application', 'octate-stream')
payload.set_payload((attach_file).read())
encoders.encode_base64(payload) #encode the attachment
#add payload header with filename
payload.add_header('Content-Decomposition', 'attachment', filename=attach_file_name)
message.attach(payload)
#Create SMTP session for sending the mail
session = smtplib.SMTP('-----', 587) #custom domain
session.starttls() #enable security
session.login(sender_address, sender_pass) #login with mail_id and password
text = message.as_string()
session.sendmail(sender_address, receiver_address, text)
session.quit()
print('Mail Sent')
The above code should set the attachment file name to "temp.txt" I believe, but it defaults to "noname" in the inbox that it is sent to.
I found a solution using MIMEApplication - it correctly names the attachment.
attach_file_name = 'Test.pdf'
attach_file=MIMEApplication(open(attach_file_name,"rb").read())
attach_file.add_header('Content-Disposition', 'attachment', filename=attach_file_name)
message.attach(attach_file)
I use AWS SES to send emails from my instance - it works when I send just messages, but when files are attached to emails, it could not send and just gets pending.
It works when I do it from a local system, but from AWS.
I'm wondering what happens when a file is attached to an email - is there somethings in AWS blocking it - or I need to use something different from smptlib of email?
I use the script below:
subject = 'xx'
body = "xx"
sender_email = "xx#gmail.com" `#this email address is confirmed in aws`
user = "xxxxx" #ses username
receiver_email = 'xxx#gmail.com' `#this email address is confirmed in aws`
password = 'xxxxx' # ses password
message = MIMEMultipart()
message["From"] = formataddr(('name', 'xxx#gmail.com'))
message["To"] = receiver_email
message["Subject"] = subject
# Add attachment to message and convert message to string
message.attach(MIMEText(body, "plain"))
filename = 'sdf.txt' #the file that will be sent.
with open(filename, "rb") as attachment:
## Add file as application/octet-stream
# Email client can usually download this automatically as attachment
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
# Encode file in ASCII characters to send by email
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
message.attach(part)
text = message.as_string()
# Log in to server using secure context and send email
context = ssl.create_default_context()
try:
with smtplib.SMTP_SSL("email-smtp.us-east-1.amazonaws.com", 465, context=context ) as server:
server.login(user, password)
server.sendmail(sender_email, receiver_email, text)
server.close()
except smtplib.SMTPException as e:
print("Error: ", e)
I modified the script, below - now it works nicely either with/without attachments in aws.
msg = MIMEMultipart()
body_part = MIMEText('xxxx', 'plain')
msg['Subject'] = 'xxx'
msg['From'] = formataddr(('xxxx', 'xxx#gmail.com'))
msg['To'] = 'xxx#gmail.com'
# Add body to email
msg.attach(body_part)
# open and read the file in binary
with open(path ,'rb') as file:
# Attach the file with filename to the email
msg.attach(MIMEApplication(file.read(), Name='xxx'))
# Create SMTP object
smtp_obj = smtplib.SMTP_SSL("email-smtp.us-east-1.amazonaws.com", 465)
# Login to the server
user = "xxx"
# Replace smtp_password with your Amazon SES SMTP password.
password = 'xxx'
smtp_obj.login(user, password)
# Convert the message to a string and send it
smtp_obj.sendmail(msg['From'], msg['To'], msg.as_string())
smtp_obj.quit()
I am trying to write a function that send an email with an attached file. At the moment, it send an email but without attachment. Can you someone comment?
msg = MIMEMultipart()
msg['From'] = my email
msg['To'] = client email address
msg['Subject'] = subject
body = content
msg.attach(MIMEText(body, 'plain'))
##### Load the address of the file which should be attached*********************************
filename = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = (("Text
files","*.txt"),("all files","*.*")))
Myfile = open(filename)
attachment = MIMEText(Myfile.read())
attachment.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(attachment)
mail = smtplib.SMTP('smtp.gmail.com', 587)
msg = f'Subject: {subject}\n\n{content}'
mail.ehlo()
mail.starttls()
mail.login('My email address', 'password')
mail.sendmail('client email', My email address, msg)
mail.close()
Thank you all in advance
First, as mentioned in my comment, you're overwriting msg here:
msg = f'Subject: {subject}\n\n{content}'
At this point, the MIMEMultipart object msg used to point to is destroyed, and you'll send only that new string. No wonder why there's no attachment: this string obviously doesn't have an attachment.
Now, you should really be using the new API of the email module, as shown in the documentation. But since you're already using the legacy API (the MIMEMultipart class, for example), you'll need to convert msg to a string, as shown here:
# This is copied straight from the last link
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you
...
part1 = MIMEText(text, 'plain') # example attachment
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
mail.sendmail(
me, you,
msg.as_string() # CONVERT TO STRING
)
I am trying to send an email with an attachment from CentOS using python. I've below code working fine on windows machine but, when I run this code it gives me an error
(110, 'Connection timed out')
def send_email(self):
print("Sending an email...")
try:
sender = 'xxxxx#domain.com'
receiver = 'yyyyy#domain.com'
msg = MIMEMultipart()
msg['From'] = sender
msg['To'] = receiver
msg['Subject'] = self.new_folder_name + 'Portal Automation testing results'
body = 'Hi, \n\n This is my email body. \n\n Thanks.'
msg.attach(MIMEText(body, 'plain'))
filename = self.zip_file_name
attachment = open(filename, 'rb')
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
# part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= " + filename)
msg.attach(part)
server = smtplib.SMTP('mail.xxxxx.com', 587)
server.starttls()
server.login(sender, "mypassword")
text = msg.as_string()
server.sendmail(sender, receiver, text)
server.quit()
print('.......')
print("Email sent.")
print("-------------------------------------------")
except Exception as e:
print('Email can not be sent. Error ====>', e)
So, I've used subprocess and it does send an email with attachment but I can't modify the message body as I want. Here is my code,
def send_email(self):
print('Sending email to xxxxxxx#domain.com')
body = 'This is email body'
file_path = '/home/Path/to/file/{}/{}'.format(self.new_folder_name, self.zip_file_name)
send_email_1 = 'echo {} | mail -s "Email testing" -a {} xxxxle#nuance.com'.format(body, file_path)
send = subprocess.call(send_email_1, shell=True)
Email Output: Hi, /n /nThis is a sample email boby. /n /n Regards
I need help with 1st code sample to make it work on CentOS or 2nd code sample where I can format my email body.
Any help is really appreciated.
I have a loop that iterates through a list of addresses and sends mail to each.
def send_mail(self, user_name, smtp_host, smtp_user, smtp_pass, smtp_port):
s = smtplib.SMTP_SSL(smtp_host[0],smtp_port[0])
s.login(smtp_user[0],smtp_pass[0])
msg = MIMEMultipart()
msg.attach(MIMEText(self.message))
msg['From'] = user_name[0]
msg['Subject'] = self.subject
for f in self.attachment_list:
part = MIMEBase('application', "octet-stream")
part.set_payload(open('temp/'+f,"rb").read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="{0}"'.format(os.path.basename(f)))
msg.attach(part)
for i,address in enumerate(Sheet.email_list):
print("Send email: " + address)
msg['To'] = address
s.sendmail(smtp_user[0], address, msg.as_string())
s.quit()
print("SMTP connection closed")
The code runs fine and sends an email to each address. However, when I view the email in Mail Application it lists: "To: " with each address. I intend for it to only list the recipient who is receiving the emails address. I played around with the code and I have determined that the issue is coming from msg['To']. I have tried to adjust it many ways, but I do not know how to make it send with only the one recipients address displayed.
msg['To'] addresses
I found the answer. I needed to replace the To header with each iteration.
if 'To' in msg:
msg.replace_header('To', address)
else:
msg['To'] = address