From 385204820aa33a3713d991a866afd8520903a96b Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 28 Jan 2015 17:27:52 +0530 Subject: [PATCH] [fix] [smtp] strip no-width-break and no-width-space characters from email addresses --- frappe/__init__.py | 5 +++-- frappe/utils/__init__.py | 6 +++++- frappe/utils/data.py | 4 ++++ frappe/utils/email_lib/email_body.py | 21 +++++++++++---------- frappe/utils/email_lib/smtp.py | 3 ++- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index a585a5d241..edebc735ab 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -490,10 +490,11 @@ def setup_module_map(): _cache.set_value("module_app", local.module_app) def get_file_items(path, raise_not_found=False, ignore_empty_lines=True): + import frappe.utils + content = read_file(path, raise_not_found=raise_not_found) if content: - # \ufeff is no-width-break, \u200b is no-width-space - content = content.replace("\ufeff", "").replace("\u200b", "").strip() + content = frappe.utils.strip(content) return [p.strip() for p in content.splitlines() if (not ignore_empty_lines) or (p.strip() and not p.startswith("#"))] else: diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index 372d3bd4ba..7987f4614c 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -64,7 +64,11 @@ def extract_email_id(email): def validate_email_add(email_str): """Validates the email string""" email = extract_email_id(email_str) - return re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", email.lower()) + match = re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", email.lower()) + if not match: + return False + + return match.group(0)==email.lower() def random_string(length): """generate a random string""" diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 952c6bf900..dd98847551 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -598,3 +598,7 @@ def unique(seq): seen = set() seen_add = seen.add return [ x for x in seq if not (x in seen or seen_add(x)) ] + +def strip(val, chars=None): + # \ufeff is no-width-break, \u200b is no-width-space + return (val or "").replace("\ufeff", "").replace("\u200b", "").strip(chars) diff --git a/frappe/utils/email_lib/email_body.py b/frappe/utils/email_lib/email_body.py index 9951623da0..a2f242b216 100644 --- a/frappe/utils/email_lib/email_body.py +++ b/frappe/utils/email_lib/email_body.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import msgprint, throw, _ -from frappe.utils import scrub_urls, get_url +from frappe.utils import scrub_urls, get_url, strip from frappe.utils.pdf import get_pdf import email.utils from markdown2 import markdown @@ -41,7 +41,7 @@ class EMail: recipients = recipients.split(',') # remove null - recipients = filter(None, (r.strip() for r in recipients)) + recipients = filter(None, (strip(r) for r in recipients)) self.sender = sender self.reply_to = reply_to or sender @@ -175,23 +175,24 @@ class EMail: msgprint(_("Alternatively, you can also specify 'auto_email_id' in site_config.json")) raise frappe.ValidationError, msg - self.sender = _validate(self.sender) - self.reply_to = _validate(self.reply_to) + self.sender = _validate(strip(self.sender)) + self.reply_to = _validate(strip(self.reply_to) or self.sender) + + self.recipients = [strip(r) for r in self.recipients] + self.cc = [strip(r) for r in self.cc] for e in self.recipients + (self.cc or []): - _validate(e.strip()) + _validate(e) def make(self): """build into msg_root""" - self.msg_root['Subject'] = self.subject.encode("utf-8") + self.msg_root['Subject'] = strip(self.subject).encode("utf-8") self.msg_root['From'] = self.sender.encode("utf-8") - self.msg_root['To'] = ', '.join([r.strip() for r in self.recipients]).encode("utf-8") + self.msg_root['To'] = ', '.join(self.recipients).encode("utf-8") self.msg_root['Date'] = email.utils.formatdate() - if not self.reply_to: - self.reply_to = self.sender self.msg_root['Reply-To'] = self.reply_to.encode("utf-8") if self.cc: - self.msg_root['CC'] = ', '.join([r.strip() for r in self.cc]).encode("utf-8") + self.msg_root['CC'] = ', '.join(self.cc).encode("utf-8") # add frappe site header self.msg_root.add_header(b'X-Frappe-Site', get_url().encode('utf-8')) diff --git a/frappe/utils/email_lib/smtp.py b/frappe/utils/email_lib/smtp.py index 6c04e0cb5f..543fd67702 100644 --- a/frappe/utils/email_lib/smtp.py +++ b/frappe/utils/email_lib/smtp.py @@ -23,7 +23,8 @@ def send(email, as_bulk=False): email.reply_to = email.sender email.sender = smtpserver.login - smtpserver.sess.sendmail(email.sender, email.recipients + (email.cc or []), + smtpserver.sess.sendmail(email.sender.encode("utf-8"), + [e.encode("utf-8") for e in (email.recipients + (email.cc or []))], email.as_string()) except smtplib.SMTPSenderRefused: