From 4391311d56a0d54b0d472adb91e26371346ecdc9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 12 Oct 2021 15:57:25 +0530 Subject: [PATCH] Sending books by e-mail: Preserve non-English characters in attached filenames --- src/calibre/gui2/email.py | 5 ++--- src/calibre/utils/smtp.py | 29 ++++++++++------------------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/calibre/gui2/email.py b/src/calibre/gui2/email.py index 09c666f753..b6b8f20668 100644 --- a/src/calibre/gui2/email.py +++ b/src/calibre/gui2/email.py @@ -18,7 +18,6 @@ from qt.core import ( from calibre.utils.smtp import (compose_mail, sendmail, extract_email_address, config as email_config) -from calibre.utils.filenames import ascii_filename from calibre.customize.ui import available_input_formats, available_output_formats from calibre.ebooks.metadata import authors_to_string from calibre.constants import preferred_encoding @@ -168,7 +167,7 @@ def email_news(mi, remove, get_fmts, done, job_manager): subjects = [_('News:')+' '+mi.title] texts = [_( 'Attached is the %s periodical downloaded by calibre.') % (mi.title,)] - attachment_names = [ascii_filename(mi.title)+os.path.splitext(attachment)[1]] + attachment_names = [mi.title+os.path.splitext(attachment)[1]] attachments = [attachment] jobnames = [mi.title] do_remove = [] @@ -408,7 +407,7 @@ class EmailMixin: # {{{ if mi.comments and gprefs['add_comments_to_email']: from calibre.utils.html2text import html2text texts[-1] += '\n\n' + _('About this book:') + '\n\n' + textwrap.fill(html2text(mi.comments)) - prefix = ascii_filename(t+' - '+a) + prefix = f'{t} - {a}' if not isinstance(prefix, unicode_type): prefix = prefix.decode(preferred_encoding, 'replace') attachment_names.append(prefix + os.path.splitext(f)[1]) diff --git a/src/calibre/utils/smtp.py b/src/calibre/utils/smtp.py index 4fa75ddb7e..db11b5a523 100644 --- a/src/calibre/utils/smtp.py +++ b/src/calibre/utils/smtp.py @@ -76,41 +76,32 @@ def create_mail(from_, to, subject, text=None, attachment_data=None, attachment_type=None, attachment_name=None): assert text or attachment_data - from email.mime.multipart import MIMEMultipart + from email.message import EmailMessage from email.utils import formatdate - from email import encoders import uuid - outer = MIMEMultipart() - outer['Subject'] = subject - outer['To'] = to + outer = EmailMessage() outer['From'] = from_ + outer['To'] = to + outer['Subject'] = subject outer['Date'] = formatdate(localtime=True) outer['Message-Id'] = "<{}@{}>".format(uuid.uuid4(), get_msgid_domain(from_)) outer.preamble = 'You will not see this in a MIME-aware mail reader.\n' if text is not None: - from email.mime.text import MIMEText if isbytestring(text): - msg = MIMEText(text) - else: - msg = MIMEText(text, 'plain', 'utf-8') - outer.attach(msg) + text = text.decode('utf-8', 'replace') + outer.set_content(text) if attachment_data is not None: - from email.mime.base import MIMEBase - from email.header import Header assert attachment_data and attachment_name try: maintype, subtype = attachment_type.split('/', 1) - except AttributeError: + except Exception: maintype, subtype = 'application', 'octet-stream' - msg = MIMEBase(maintype, subtype, name=Header(attachment_name, 'utf-8').encode()) - msg.set_payload(attachment_data) - encoders.encode_base64(msg) - msg.add_header('Content-Disposition', 'attachment', - filename=Header(attachment_name, 'utf-8').encode()) - outer.attach(msg) + if isinstance(attachment_data, str): + attachment_data = attachment_data.encode('utf-8') + outer.add_attachment(attachment_data, maintype=maintype, subtype=subtype, filename=attachment_name) return outer