diff --git a/frappe/email/bulk.py b/frappe/email/bulk.py index 2c84fe2b70..be4b08c5f1 100644 --- a/frappe/email/bulk.py +++ b/frappe/email/bulk.py @@ -56,14 +56,15 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc for email in filter(None, list(set(recipients))): if email not in unsubscribed: - unsubscribe_url = get_unsubcribed_url(reference_doctype, reference_name, email, - unsubscribe_method, unsubscribe_params) + if reference_doctype: + unsubscribe_url = get_unsubcribed_url(reference_doctype, reference_name, email, + unsubscribe_method, unsubscribe_params) - # add to queue - updated = add_unsubscribe_link(formatted, email, reference_doctype, reference_name, - unsubscribe_url, unsubscribe_message) + # add to queue + updated = add_unsubscribe_link(formatted, email, reference_doctype, reference_name, + unsubscribe_url, unsubscribe_message) - text_content += "\n" + _("Unsubscribe link: {0}").format(unsubscribe_url) + text_content += "\n" + _("Unsubscribe link: {0}").format(unsubscribe_url) add(email, sender, subject, updated, text_content, reference_doctype, reference_name, attachments, reply_to, cc, message_id) diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 642da61353..488a2f3757 100644 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -103,35 +103,43 @@ class EmailAccount(Document): pop3 = self.get_pop3() incoming_mails = pop3.get_messages() + exceptions = [] for raw in incoming_mails: - email = Email(raw) + try: + email = Email(raw) - communication = frappe.get_doc({ - "doctype": "Communication", - "subject": email.subject, - "content": email.content, - "sent_or_received": "Received", - "sender_full_name": email.from_real_name, - "sender": email.from_email, - "recipients": email.mail.get("To"), - "email_account": self.name, - "communication_medium": "Email" - }) + communication = frappe.get_doc({ + "doctype": "Communication", + "subject": email.subject, + "content": email.content, + "sent_or_received": "Received", + "sender_full_name": email.from_real_name, + "sender": email.from_email, + "recipients": email.mail.get("To"), + "email_account": self.name, + "communication_medium": "Email" + }) - self.set_thread(communication, email) + self.set_thread(communication, email) - communication.insert(ignore_permissions = 1) + communication.insert(ignore_permissions = 1) - # save attachments - email.save_attachments_in_doc(communication) + # save attachments + email.save_attachments_in_doc(communication) - if self.enable_auto_reply and getattr(communication, "is_first", False): - self.send_auto_reply(communication, email) + if self.enable_auto_reply and getattr(communication, "is_first", False): + self.send_auto_reply(communication, email) - # notify all participants of this thread - # convert content to HTML - by default text parts of replies are used. - communication.content = markdown2.markdown(communication.content) - communication.notify(attachments=email.attachments, except_recipient = True) + # notify all participants of this thread + # convert content to HTML - by default text parts of replies are used. + communication.content = markdown2.markdown(communication.content) + communication.notify(attachments=email.attachments, except_recipient = True) + + except Exception, e: + exceptions.append(frappe.get_traceback()) + + if exceptions: + raise Exception, exceptions def set_thread(self, communication, email): """Appends communication to parent based on thread ID. Will extract @@ -173,7 +181,18 @@ class EmailAccount(Document): parent.set_sender(email.from_email) parent.flags.ignore_mandatory = True - parent.insert(ignore_permissions=True) + + try: + parent.insert(ignore_permissions=True) + + except frappe.DuplicateEntryError: + + if frappe.get_meta(self.append_to).get_field("email_id"): + # assume that duplicate entry is due to email_id field! + parent = frappe.get_doc(self.append_to, { "email_id": email.from_email }) + + else: + raise communication.is_first = True