AttributeError: module 'email.encoders' has no attribute 'endcode_base64' - python

New to python. Trying to send an email with attachment but keep receiving the following error:
AttributeError: module 'email.encoders' has no attribute
'endcode_base64'
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
print("Enter recipients addrss")
toaddr = input()
print("Enter senders addrss")
fromaddr = input()
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
print("Enter subjectline")
msg['Subject'] = input()
print("Type message")
body = input()
msg.attach(MIMEText(body, 'plain'))
Attach file: convert file to Base64 to send text files, pdf, images, audio and video files.
print("Enter name of file with its extension")
Enter 'none' if no attachments
print("Enter filename, No attachments? Enter none")
filename = input(" ")
if filename != "none":
print("Enter path of file")
attachment = open(input(), "rb")
part = MIMEBase("application", "octet-stream")
part.set_payload((attachment).read())
encoders.endcode_base64(part)
part.add_header('Content-Disposition',"attachment;filename= %s" %
filename)
msg.attach(part)
if toaddr.endswith(gmail):
mail= smtplib.SMTP('smtp.gmail.com',587)
mail.starttls()
mail.login(input(), input())
text = msg.as_string()
mail.sendmail(fromaddr, toaddr, text)
mail.close()
else:
if toaddr.endswith(outlook):
mail= smtplib.SMTP('smtp-mail.outlook.com',587)
mail.starttls()
mail.login(input(), input())
text = msg.as_string()
mail.sendmail(fromaddr, toaddr, text)
mail.close()

Related

How to edit .eml file generated with email.generator in Outlook?

I have a code, that generate me .eml message file which I open in Outlook. But the message file is uneditable (can't edit this file). E.g.: I want to add new sender or recepiant, but I can't do that.
Does anybody know, how fix this problem, or may be there is another way to create message file?
import email
from email import generator
from email.mime.text import MIMEText
from email.encoders import encode_base64
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
import json
import SQL_from_DB
import os
import re
def create_mail(attach_file_name, message_json, mail_template_path, save_path, database, db_username, db_password, driver):
file_name_mail_template = mail_template_path + re.sub("QWE:\[.*?\]\s+","",message_json['message']) + '.txt'
try:
mail_template_file = open(file_name_mail_template.encode('utf-8'), 'r', encoding="utf-8")
except:
print("Ошибка открытия шаблона пиьсма \"" + re.sub("QWE:\[.*?\]\s+","",message_json['message']) + ".txt\"")
sys.exit()
mail_template_text = mail_template_file.read()
for var, value in message_json.items():
mail_template_text = mail_template_text.replace('${' + str(var) + '}', str(value))
# print(mail_template_text)
msg = MIMEMultipart()
msg['Subject'] = message_json['message']
msg['From'] = 'qwe#qwe.qwe'
msg['To'] = SQL_from_DB.SQL_select(database, db_username, db_password, driver, message_json['DOMAINNAME'])
#add attachment
attach_file = open(attach_file_name.encode('utf-8'), 'rb')
attachment = MIMEBase("application", "msword")
#attachment = MIMEBase("application", "pdf")
attachment.set_payload(attach_file.read())
attach_file.close()
encode_base64(attachment)
attachment.add_header('Content-Disposition','attachment',filename='Events' + ".zip")
msg.attach(attachment)
#текст письма
msg.attach(MIMEText(mail_template_text, 'html'))
#save message file
with open(save_path.encode("utf-8"), 'w') as out:
gen = email.generator.Generator(out)
gen.flatten(msg)
return(save_path)
To generate an editable Outlook file, just need generate not .eml but .emltpl (Outlook message template file).
#save message file
with open('/save_path/message.emltpl', 'w') as out:
gen = email.generator.Generator(out)
gen.flatten(msg)
return(save_path)

Python 3 sending congratulations to customer

How I may send birthday congratulations with attached jpg file to our cutomers by email?
I write script, he show notifications:
import time
import os
birthdayFile = 'birthdays.csv'
def checkTodaysBirthdays():
fileName = open(birthdayFile, 'r')
today = time.strftime('%m%d')
flag = 0
for line in fileName:
if today in line:
line = line.split(' ')
flag =1
os.system('notify-send "Birthdays Today: ' + line[1]
+ ' ' + line[2] + '"')
if flag == 0:
os.system('notify-send "No Birthdays Today!')
But I dont know, how send congrats by email.
File birthdays.csv contain next row: date, name, email
You can use smtplib. Below is an implementation of the simple notification system using a class, to utilize clean context-manager behavor:
import datetime
import smtplib, csv
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
class SendEmail:
def __init__(self, _to, _from = 'youremail#domaim.com', subject = 'Happy Birthday!', attachment = 'birthday.jpg'):
self._to = _to
self._from = _from
self._subject = subject
self.attachment = attachment
def __enter__(self):
msg = MIMEMultipart()
for part in ['Subject', 'From', 'To']:
msg[part] = getattr(self, f'_{i.lower()}')
part = MIMEBase('application', "octet-stream")
part.set_payload(open(self.attachment, "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', f'attachment; filename="{self.attachment}"')
msg.attach(part)
server = smtplib.SMTP(self.EMAIL_SERVER)
server.sendmail(self.EMAIL_FROM, self.EMAIL_TO, msg.as_string())
return self
def __exit__(self, *args):
pass
#classmethod
def send_bulk(cls, users:list):
for date, name, email in users:
_d = datetime.datetime.now()
if _d.month in date and _d.day in date:
with cls(email, subject = f'Happy Birthday, {name}!') as f:
pass
with open('filename.csv') as f:
SendEmail.send_bulk(csv.reader(f))

How to continue code if user does not select a file in tkinter

I'm new to tkinter and trying to create an email gui. So far everything works but after adding a select file functionality to it the program will only work if the user selects a file. I get the error
'GetInfo' object has no attribute 'fname'
Which I'm assuming means that since fname (file name) has no value added to it the program won't continue. I tried to use a try/except thing here:
try:
filename = self.fname
attachment = open(self.fname, "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)
except:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.ehlo()
server.login(self.frominf.get(), self.passinf.get()) #sender email, password
text = msg.as_string()
server.sendmail(self.frominf.get(), self.toinf.get(), text)
server.quit()
# STOP TIMER
elapsed_time = timer() - start # in seconds
print ("Email took " + (str(elapsed_time)) + " seconds to send, sent to " + self.toinf.get() )
time.sleep(0.5)
root.destroy()
But this pretty much did the opposite, giving an error if I did supply a file.
So my question is: how can I let the user decide if they want to supply a file or not?
Here is my whole code:
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter import ttk
import time
import datetime
import smtplib
from timeit import default_timer as timer
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
#colors
darkred = (139, 0, 0)
grey = (90, 90, 90)
root = Tk()
root.title("Email")
class GetInfo:
def __init__(self, master):
#window size
master.minsize(width=250, height=75)
#senders email
Label(root, text="Your email").pack(fill=X)
self.frominf = Entry(master)
self.frominf.pack(fill=X)
#sending to email
Label(root, text="Sending to").pack(fill=X)
self.toinf = Entry(root)
self.toinf.pack(fill=X)
#subject line
Label(root, text="Subject").pack(fill=X)
self.subinf = Entry(root)
self.subinf.pack(fill=X)
#add file
Label(root, text="File?").pack(fill=X)
file_button = Button(root, text="Click to browse files", command= self.Load_file, height = 1, bg="grey")
file_button.pack(fill=X)
#senders password
Label(root, text="Your password").pack(fill=X)
self.passinf = Entry(master, show="*")
self.passinf.pack(fill=X)
#body
Label(root, text="Body of email").pack(fill=X)
self.bodyinf = Text(root)
self.bodyinf.pack(fill=X)
#submit button
submit_button = Button(root, text="Submit(click when done)", command=self.send_email, height = 2, bg="darkred")
submit_button.pack(fill=X)
def Load_file(self):
self.fname = askopenfilename(filetypes=(("All Files","*.*"),
("HTML files", "*.html;*.htm"),
("Template files", "*.tplate") ))
def send_email(self):
# START TIMER
start = timer()
msg = MIMEMultipart()
msg['From'] = self.frominf.get()
msg['To'] = self.toinf.get()
msg['Subject'] = self.subinf.get()
body = self.bodyinf.get('1.0', END)
msg.attach(MIMEText(body, 'plain'))
filename = self.fname
attachment = open(self.fname, "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)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.ehlo()
server.login(self.frominf.get(), self.passinf.get()) #sender email, password
text = msg.as_string()
server.sendmail(self.frominf.get(), self.toinf.get(), text)
server.quit()
# STOP TIMER
elapsed_time = timer() - start # in seconds
print ("Email took " + (str(elapsed_time)) + " seconds to send, sent to " + self.toinf.get() )
time.sleep(0.5)
root.destroy()
app = GetInfo(root)
root.mainloop()
Use this try and catch. If the filename exist, the try part code will be executed. If there's no file selected, it will go to the catch part and will do nothing, just continue with the code without showing any error.
try:
filename = self.fname
attachment = open(self.fname, "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)
except:
pass
If I understood the question correctly, You can check whether self.fname exists. One way to do it:
if self.fname:
attachment = open(self.fname, "rb")
Of course, You need to check later if You have attachment, to avoid another bug. So, further:
if self.fname:
attachment = open(self.fname, "rb")
# This part of code also should go under condition check
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)
I would add the self.fname attribute at the start of the program and set it as:
self.fname = ""
Then I would change this line:
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
To an if statement like this:
if self.fname != "":
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
else:
part.add_header('Content-Disposition')
This should prevent the error when a file is not selected.
I cannot test this right now but should be functional.

TypeError: object of type 'method' has no len() | Trying to attach file to email msg

I'm using Python 3 and I'm trying to attach a file to an email message. I'm pretty new at MIME and SMTP stuff.
So this is my function:
def func():
path = mypath
for file in glob.glob(path + "\\happy*"):
print(file)
sender = myemail
senderto = someonesemail
msg = MIMEMultipart('alternative')
msg['Subject'] = 'The File'
msg['From'] = sender
msg['To'] = senderto
body = "File"
msg.attach(MIMEText(body, 'plain'))
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(file, encoding='charmap').read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % file)
msg.attach(part)
global smtpSettings
smtpSettings = smtplib.SMTP(host=myhost, port=587)
print("Step 1 Complete")
smtpSettings.login(smtpusername, smtppassword)
print("Step 2 Complete")
smtpSettings.sendmail(sender, senderto, msg.as_string)
print("Step 3 Complete")
smtpSettings.quit()
print("Success")
Side note: senderto = receiver.
The output I get is:
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
return self.func(*args)
File "C:/Users/Luis/Desktop/PYTHON/smtptestes.py", line 73, in func
smtpSettings.sendmail(sender, senderto, msg.as_string)
File "C:\Python34\lib\smtplib.py", line 769, in sendmail
esmtp_opts.append("size=%d" % len(msg))
TypeError: object of type 'method' has no len()
Fix in step 3, change
smtpSettings.sendmail(sender, senderto, msg.as_string)
to
smtpSettings.sendmail(sender, senderto, msg.as_string())
because as_string is a method
I'm the maintainer of yagmail, it's a package that makes it a lot easier to send emails (with or without attachments).
import yagmail
yag = yagmail.SMTP(myemail, 'mypassword')
yag.send(to = someonesemail, subject = 'The File', contents = ['File', file])
Only three lines needed for the sending of the email. Nice!
The contents will smartly guess that the file variable string points to a file, and thus attach it.
Full code might be:
import yagmail
import glob
def func(path, user, pw, ):
subject = 'The File'
body = "File"
yag = yagmail.SMTP(user, pw, host = myhost)
for fname in glob.glob(path + "\\happy*"):
yag.send(someonesemail, subject, [body, fname])
func(mypath, smtpusername, smtppassword)

Create a .eml file in Python [duplicate]

I am trying to generate emails using the standard email library and save them as .eml files.
I must not be understanding how email.generator works because I keep getting the error 'AttributeError: 'str' object has no attribute 'write.'
from email import generator
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
active_dir = 'c:\\'
class Gen_Emails(object):
def __init__(self):
self.EmailGen()
def EmailGen(self):
sender = 'sender'
recepiant = 'recipiant'
subject = 'subject'
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = recepiant
html = """\
<html>
<head></head>
<body>
<p> hello world </p>
</body>
</html>
"""
part = MIMEText(html, 'html')
msg.attach(part)
self.SaveToFile(msg)
def SaveToFile(self,msg):
out_file = active_dir
gen = generator.Generator(out_file)
gen.flatten(msg)
Any ideas?
You are supposed to pass an open file (in write mode) to Generator(). Currently you pass it just a string, which is why it fails when it tries to call .write() on the string.
So do something like this:
import os
cwd = os.getcwd()
outfile_name = os.path.join(cwd, 'message.eml')
class Gen_Emails(object):
# ...
def SaveToFile(self,msg):
with open(outfile_name, 'w') as outfile:
gen = generator.Generator(outfile)
gen.flatten(msg)
Note: with open(outfile_name, 'w') as outfile opens the file at the path outfile_name in write mode and assigns the file pointer to the open file to outfile. The context manager also takes care of closing the file for you after you exit the with block.
os.path.join() will join paths in a cross-plattform way, which is why you should prefer it over concatenating paths by hand.
os.getcwd() will return your current working directory. If you want to your file to be saved somewhere else just change it out accordingly.
Here is a modified solution that works with extra headers too. (This was tested with Python 2.6)
import os
from email import generator
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
html_data = ...
msg = MIMEMultipart('alternative')
msg['Subject'] = ...
msg['From'] = ...
msg['To'] = ...
msg['Cc'] = ...
msg['Bcc'] = ...
headers = ... dict of header key / value pairs ...
for key in headers:
value = headers[key]
if value and not isinstance(value, basestring):
value = str(value)
msg[key] = value
part = MIMEText(html_data, 'html')
msg.attach(part)
outfile_name = os.path.join("/", "temp", "email_sample.eml")
with open(outfile_name, 'w') as outfile:
gen = generator.Generator(outfile)
gen.flatten(msg)
print "=========== DONE ============"

Categories

Resources