diff --git a/frappe/__init__.py b/frappe/__init__.py index 6d1afb1fe6..a8d546843c 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -372,7 +372,7 @@ def sendmail(recipients=[], sender="", subject="No Subject", message="No Message unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, attachments=None, content=None, doctype=None, name=None, reply_to=None, cc=[], message_id=None, in_reply_to=None, send_after=None, expose_recipients=None, - send_priority=1, communication=None, retry=1, now=None, read_receipt=None): + send_priority=1, communication=None, retry=1, now=None, read_receipt=None, is_notification=False): """Send email using user's default **Email Account** or global default **Email Account**. @@ -411,7 +411,7 @@ def sendmail(recipients=[], sender="", subject="No Subject", message="No Message unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, unsubscribe_message=unsubscribe_message, attachments=attachments, reply_to=reply_to, cc=cc, message_id=message_id, in_reply_to=in_reply_to, send_after=send_after, expose_recipients=expose_recipients, send_priority=send_priority, - communication=communication, now=now, read_receipt=read_receipt) + communication=communication, now=now, read_receipt=read_receipt, is_notification=is_notification) whitelisted = [] guest_methods = [] diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index cb4a2d3773..93fa374705 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -196,6 +196,8 @@ class Communication(Document): '''Look into the status of Email Queue linked to this Communication and set the Delivery Status of this Communication''' delivery_status = None status_counts = Counter(frappe.db.sql_list('''select status from `tabEmail Queue` where communication=%s''', self.name)) + if self.sent_or_received == "Received": + return if status_counts.get('Not Sent') or status_counts.get('Sending'): delivery_status = 'Sending' diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 41b773701f..ecbf2bdb6a 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -61,7 +61,8 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "reference_doctype": doctype, "reference_name": name, "message_id":get_message_id().strip(" <>"), - "read_receipt":read_receipt + "read_receipt":read_receipt, + "has_attachment": 1 if attachments else 0 }) comm.insert(ignore_permissions=True) @@ -157,7 +158,8 @@ def _notify(doc, print_html=None, print_format=None, attachments=None, unsubscribe_message=unsubscribe_message, delayed=True, communication=doc.name, - read_receipt = doc.read_receipt + read_receipt=doc.read_receipt, + is_notification=True if doc.sent_or_received =="Received" else False ) def update_parent_status(doc): @@ -418,8 +420,6 @@ def sendmail(communication_name, print_html=None, print_format=None, attachments for i in xrange(3): try: communication = frappe.get_doc("Communication", communication_name) - if communication.sent_or_received == "Received": - communication.message_id = None communication._notify(print_html=print_html, print_format=print_format, attachments=attachments, recipients=recipients, cc=cc) diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index 39b436fa4c..a20484b8ab 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -183,12 +183,14 @@ class EMail: sender_name, sender_email = email.utils.parseaddr(self.sender) self.sender = email.utils.formataddr((sender_name or self.email_account.name, self.email_account.email_id)) - def set_message_id(self, message_id): + def set_message_id(self, message_id, is_notification=False): if message_id: self.msg_root["Message-Id"] = '<' + message_id + '>' else: self.msg_root["Message-Id"] = get_message_id() self.msg_root["isnotification"] = '' + if is_notification: + self.msg_root["isnotification"] = '' def set_in_reply_to(self, in_reply_to): """Used to send the Message-Id of a received email back as In-Reply-To""" diff --git a/frappe/email/queue.py b/frappe/email/queue.py index ab5946b66d..6d33f0c6a5 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -20,7 +20,7 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, attachments=None, reply_to=None, cc=[], message_id=None, in_reply_to=None, send_after=None, expose_recipients=None, send_priority=1, communication=None, now=False, read_receipt=None, - queue_separately=False, add_unsubscribe_link=1): + queue_separately=False, is_notification=False, add_unsubscribe_link=1): """Add email to sending queue (Email Queue) :param recipients: List of recipients. @@ -39,6 +39,7 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc :param communication: Communication link to be set in Email Queue record :param now: Send immediately (don't send in the background) :param queue_separately: Queue each email separately + :param is_notification: Marks email as notification so will not trigger notifications from system :param add_unsubscribe_link: Send unsubscribe link in the footer of the Email, default 1. """ if not unsubscribe_method: @@ -109,6 +110,7 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc expose_recipients=expose_recipients, read_receipt=read_receipt, queue_separately=queue_separately, + is_notification = is_notification, now=now) @@ -151,7 +153,7 @@ def get_email_queue(recipients, sender, subject, **kwargs): email_account=kwargs.get('email_account'), expose_recipients=kwargs.get('expose_recipients')) - mail.set_message_id(kwargs.get('message_id')) + mail.set_message_id(kwargs.get('message_id'),kwargs.get('is_notification')) if kwargs.get('read_receipt'): mail.msg_root["Disposition-Notification-To"] = sender if kwargs.get('in_reply_to'): diff --git a/frappe/email/receive.py b/frappe/email/receive.py index 7bceaab1be..8f16b4cc9d 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -265,11 +265,16 @@ class Email: self.message_id = (self.mail.get('Message-ID') or "").strip(" <>") if self.mail["Date"]: - utc = email.utils.mktime_tz(email.utils.parsedate_tz(self.mail["Date"])) - utc_dt = datetime.datetime.utcfromtimestamp(utc) - self.date = convert_utc_to_user_timezone(utc_dt).strftime('%Y-%m-%d %H:%M:%S') + try: + utc = email.utils.mktime_tz(email.utils.parsedate_tz(self.mail["Date"])) + utc_dt = datetime.datetime.utcfromtimestamp(utc) + self.date = convert_utc_to_user_timezone(utc_dt).strftime('%Y-%m-%d %H:%M:%S') + except: + self.date = now() else: self.date = now() + if self.date > now(): + self.date = now() def parse(self): """Walk and process multi-part email.""" @@ -294,21 +299,34 @@ class Email: # use X-Original-Sender if available, as gmail sometimes modifies the 'From' _from_email = self.mail.get("X-Original-From") or self.mail["From"] _from_email, encoding = decode_header(_from_email)[0] + _reply_to, _reply_to_encoding = decode_header(self.mail.get("Reply-To"))[0] if encoding: _from_email = _from_email.decode(encoding) else: _from_email = _from_email.decode('utf-8') + + if _reply_to_encoding: + _reply_to = _from_email.decode(encoding) + else: + _reply_to = _from_email.decode('utf-8') - self.from_email = extract_email_id(_from_email) - self.from_real_name = email.utils.parseaddr(_from_email)[0] + if _reply_to and not frappe.db.get_value('Email Account', {"email_id":_reply_to}, 'email_id'): + self.from_email = extract_email_id(_reply_to) + else: + self.from_email = extract_email_id(_from_email) + + if self.from_email: + self.from_email = self.from_email.lower() + + self.from_real_name = email.utils.parseaddr(_from_email)[0] if "@" in _from_email else _from_email def set_content_and_type(self): self.content, self.content_type = '[Blank Email]', 'text/plain' if self.html_content: self.content, self.content_type = self.html_content, 'text/html' else: - self.content, self.content_type = EmailReplyParser.parse_reply(self.text_content), 'text/plain' + self.content, self.content_type = EmailReplyParser.read(self.text_content).text.replace("\n","\n\n"), 'text/plain' def process_part(self, part): """Parse email `part` and set it to `text_content`, `html_content` or `attachments`.""" @@ -323,7 +341,7 @@ class Email: # sent by outlook when another email is sent as an attachment to this email self.show_attached_email_headers_in_content(part) - elif part.get_filename(): + elif part.get_filename() or 'image' in content_type: self.get_attachment(part) def show_attached_email_headers_in_content(self, part):