I am trying to send mail using python script. I tried without attachment it is working.
Now i tried with attachment i am getting assertion error.
Below is the code:
import smtplib
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 os
import time
import random
msg_from = "xyz#abc.com"
to = "xyz#abc.com"
text = "test-Hello"
subject = "Test"
f = "output1.pdf"
def generate_message_id(msg_from):
domain = msg_from.split("#")[1]
r = "%s.%s" % (time.time(), random.randint(0, 100))
mid = "<%s#%s>" % (r, domain)
return mid
def send_mail(msg_from, to, subject, text,
files=[],server="10.10.10.10", debug=False):
assert type(to)==list
assert type(files)==list
msg = MIMEMultipart()
msg['From'] = msg_from
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
text = text.encode("utf-8")
text = MIMEText(text, 'plain', "utf-8")
msg.attach(text)
msg.add_header('Message-ID', generate_message_id(msg_from))
for file in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(f,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
for file in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(f,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(file))
msg.attach(part)
if not debug:
smtp = smtplib.SMTP(server)
smtp.sendmail(msg_from, to, msg.as_string())
smtp.close()
return msg
send_mail(msg_from, to, subject, text,files=[],server="10.10.10.10", debug=False)
Error i am getting:
Traceback (most recent call last):
File "testmail1.py", line 53, in <module>
send_mail(msg_from, to, subject, text,files=[],server="10.10.10.10", debug=False)
File "testmail1.py", line 24, in send_mail
assert type(to)==list
AssertionError
I am using from linux os and using python 2.7
Please help me to fix
Your to field should be a list, because you could theoretically send your email to multiple persons. So I'd suggest:
to = ["xyz#abc.com"]
The send_mail method checks first if your to field is a list, that's why you're getting the error.
Also check out the documentation
Related
I have this script that sends emails with multiple attachments to multiple users. However, the attachments' file names are set as their path.
Received files
Terminal Output
How can I set their names as the actual file names, thanks.
"""
import os
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
from email.MIMEBase import MIMEBase
from email import Encoders
#Set up crap for the attachments
files = "/tmp/test/dbfiles"
filenames = [os.path.join(files, f) for f in os.listdir(files)]
#print filenames
#Set up users for email
gmail_user = "joe#email.com"
gmail_pwd = "somepasswd"
recipients = ['recipient1','recipient2']
#Create Module
def mail(to, subject, text, attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = ", ".join(recipients)
msg['Subject'] = subject
msg.attach(MIMEText(text))
#get all the attachments
for file in filenames:
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(file, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % file)
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()
#send it
mail(recipients,
"Todays report",
"Test email",
filenames)
"""
there might be a solution in this link:
Python email MIME attachment filename
Basically what the solution is according to that post is change your this line:
part.add_header('Content-Disposition', 'attachment; filename="%s"' % file)
to this line :
part.add_header('Content-Disposition', 'attachment', filename=AFileName)
Which comes down to this final change:
#get all the attachments
for file in filenames:
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(file, 'rb').read())
Encoders.encode_base64(part)
***part.add_header('Content-Disposition', 'attachment', filename=file)***
msg.attach(part)
Documentation on how to use add_header
Hope that helps! :D
Update
Having this in your for loop should give you the filenames:
for file in filenames:
actual_filenames = os.path.basename(file)
#Your code
part.add_header('Content-Disposition', 'attachment', filename=actual_filenames)
if it is in the same directory:
import os
for f in os.listdir('.'):
fn, fext = os.path.splitext(f)
I think the problem is in parameter server=... what should I put here?
import smtplib
import os
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders
def send_mail(send_from, send_to, subject, text, files=[], server=r'\\myserver\User\name\PythonProject\'):
assert type(send_to)==['sendto#.com']
assert type(files)==['File Name.xlsx']
msg = MIMEMultipart()
msg['From'] = "sendfrom#.com"
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for f in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(files,"rb").read() )
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
msg.attach(part)
smtp = smtplib.SMTP('1.1.1.1: 25')
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
This code has number of problems.
The default value of server in the function signature
the string ends with \', which escapes the closing quote: remove it or escape it (the "r" prefix escapes the backslashes inside the string, but the terminal backslash is interpreted as escaping the closing quote and so outside the string)
server is not used in the function
Using a mutable default value like files=[] is usually a bad idea; better to use files=None and check the value in your code before trying to iterate over it
the assert statements don't work.
use isinstance rather than type to check object types
part.set_payload( open(files,"rb").read() ) is trying to open the list of files, it only needs to open the current file in the loop: open(f, ...)
Here is a "fixed" version of the code
def send_mail(
send_from,
send_to,
subject,
text,
files=None,
server=r"\\myserver\User\name\PythonProject\\",
):
assert isinstance(send_to, list)
assert isinstance(files, list)
msg = MIMEMultipart()
msg["From"] = "sendfrom#.com"
msg["To"] = COMMASPACE.join(send_to)
msg["Date"] = formatdate(localtime=True)
msg["Subject"] = subject
msg.attach(MIMEText(text))
if files is not None:
for f in files:
part = MIMEBase("application", "octet-stream")
part.set_payload(open(f, "rb").read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition", 'attachment; filename="%s"' % os.path.basename(f)
)
msg.attach(part)
smtp = smtplib.SMTP('1.1.1.1:25')
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
import smtplib, os
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import formatdate
from email import encoders
os.chdir(path)
def send_mail(send_from,send_to,subject,text,files,server,port,username='',password='',isTls=True):
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = send_to
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = 'Test'
msg.attach(MIMEText(text))
part = MIMEBase('application', "octet-stream")
part.set_payload(open("Olaf.xlsx", "rb").read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment;
filename="Olaf.xlsx"')
msg.attach(part)
smtp = smtplib.SMTP('smtp.web.de', 587)
smtp.starttls()
smtp.login('test#test.de', 'pw')
At this part the error occurs: NameError: name 'msg' is not defined. But whats wrong?
Here is where I got the code from: add excel file attachment when sending python email
smtp.sendmail('xy','xyz', msg.as_string())
smtp.quit()
You can try the below code:
import smtplib, os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders
from email.mime.text import MIMEText
emaillist=['to#gmail.com'] # Receipient email address
msg = MIMEMultipart('mixed')
msg['Subject'] = 'Arrest Warrent' # mail subject line
msg['From'] = 'xyz#gmail.com' # From email address
msg['To'] = ', '.join(emaillist)
part = MIMEBase('application', "octet-stream")
# Provide the path of the file to be attached in the mail
part.set_payload(open('C:'+os.sep+'Users'+os.sep+'abhijit'+os.sep+'Desktop'+os.sep+'WarrentDetails.txt', "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="WarrentDetails.txt"')
msg.attach(part)
msg.add_header('To', msg['From'])
text = "Dear Sir, \n\n An arrest warrent has been generated due to XYZ reason by ZZZ complain.\n YOU MUST APPEAR IN PERSON TO RESOLVE THIS MATTER. \n\n Regards,\n FBI :)"
part1 = MIMEText(text, 'plain')
msg.attach(part1)
# provide SMTP details of the host and its port number
server = smtplib.SMTP_SSL("smtp.gmail.com",465)
# If the host supports TLS then enable the below 2 lines of code
# server.ehlo()
# server.starttls()
server.login("xyz#gmail.com", "password")
server.sendmail(msg['From'], emaillist , msg.as_string())
More details on this can be found at this blog.
I'm using python 2.7.3. and I have following code for send emails with attached file.
# coding: cp1251
import os
import smtplib
from email import Encoders
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.Utils import formatdate
def sendEmail(to_address, mail_settings, attachment_file_path, subject = 'my_subject'):
HOST = mail_settings['host']
port = mail_settings['port']
username = mail_settings['login']
password = mail_settings['pass']
msg = MIMEMultipart()
msg["From"] = mail_settings['from_address']
msg["To"] = ','.join(to_address)
msg["Subject"] = subject.decode('cp1251')
msg['Date'] = formatdate(localtime=True)
msg['Content-Type'] = "text/html; charset=cp1251"
# attach a file
part = MIMEBase('application', "octet-stream")
part.set_payload( open(attachment_file_path,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attachment_file_path))
msg.attach(part)
server = smtplib.SMTP(host=HOST, port=port)
try:
failed = server.sendmail(mail_settings['from_address'], to_address, msg.as_string())
print('sent')
server.close()
except Exception, e:
errorMsg = "Unable to send email. Error: %s" % str(e)
print(errorMsg)
My problem is that exchange users who receive emails through this code can't see attachment file name if it has russian letters (for example пример.txt), otherwise if it has english letters everything works fine for them.
I faced with this problem only with customers who use exchange (gmail works fine).
What i'm doing wrong? where should I change encoding?
I found the solution finally. I just set encoding for header.
mail_coding = 'utf-8'
att_header = Header(os.path.basename(attachment_file_path), mail_coding);
part.add_header('Content-Disposition', 'attachment; filename="%s"' % att_header)
Came here with the same problem and Savva Sergey's own solution didn't work for me.
Encoding with os.path.basename(email_attach1).encode('utf-8') was useless too.
And I'm positive that's happened because of python's version. Mine is 3.8 and while I'm doing almost the same, here it is what's works:
import os
from email.mime.application import MIMEApplication
email_attach1 = './path/to/文件.pdf'
part = MIMEApplication(
open(email_attach1,"rb").read(),
Name=os.path.basename(email_attach1),_subtype="pdf"
)
part.add_header('Content-Disposition',
'attachment',filename=os.path.basename(email_attach1))
I am trying to send mail using Python 3.2. My code is as follows:
#from email import Encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
import os
import smtplib
from base64 import encode
from email import encoders
def sendMail(to, subject, text, files=[],server="smtp.mydomain.com"):
assert type(to)==list
assert type(files)==list
fro = "From <myemail#mydomain.com>"
msg = MIMEMultipart()
msg['From'] = fro
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for file in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(file,"rb").read() )
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(file))
msg.attach(part)
smtp = smtplib.SMTP_SSL(server, 465)
smtp.ehlo()
smtp.set_debuglevel(1)
smtp.ehlo()
smtp.login("myemail#mydomain.com", "mypassword")
smtp.ehlo()
smtp.sendmail(fro, to, msg.as_string() )
smtp.close()
print("Email send successfully.")
sendMail(
["recipient"],
"hello","cheers",
[]
)
It gives me following error:
raise SMTPSenderRefused(code, resp, from_addr)
smtplib.SMTPSenderRefused: (501, b'5.7.1 <myemail#mydomain.com>... Permission denied', 'myemail#mydomain.com')
Does anybody know how to solve this problem?
Thanks in advance.
As the error says: you need to call the connect method on the smtplib.SMTP_SSL instance before you try to use it. smtplib.SMTP_SSL does not automatically connect (and neither does smtplib.SMTP.)