[mailbox] cleaned up, added tests #561
This commit is contained in:
parent
4d4f146fc8
commit
ac0a9deaf1
24 changed files with 280 additions and 354 deletions
|
|
@ -225,22 +225,22 @@ def get_request_header(key, default=None):
|
|||
|
||||
def sendmail(recipients=(), sender="", subject="No Subject", message="No Message",
|
||||
as_markdown=False, bulk=False, ref_doctype=None, ref_docname=None,
|
||||
add_unsubscribe_link=False, attachments=None):
|
||||
add_unsubscribe_link=False, attachments=None, content=None):
|
||||
|
||||
if bulk:
|
||||
import frappe.email.bulk
|
||||
frappe.email.bulk.send(recipients=recipients, sender=sender,
|
||||
subject=subject, message=message, ref_doctype = ref_doctype,
|
||||
subject=subject, message=content or message, ref_doctype = ref_doctype,
|
||||
ref_docname = ref_docname, add_unsubscribe_link=add_unsubscribe_link, attachments=attachments)
|
||||
|
||||
else:
|
||||
import frappe.email
|
||||
if as_markdown:
|
||||
frappe.email.sendmail_md(recipients, sender=sender,
|
||||
subject=subject, msg=message, attachments=attachments)
|
||||
subject=subject, msg=content or message, attachments=attachments)
|
||||
else:
|
||||
frappe.email.sendmail(recipients, sender=sender,
|
||||
subject=subject, msg=message, attachments=attachments)
|
||||
subject=subject, msg=content or message, attachments=attachments)
|
||||
|
||||
logger = None
|
||||
whitelisted = []
|
||||
|
|
|
|||
|
|
@ -801,7 +801,7 @@ def run_tests(app=None, module=None, doctype=None, verbose=False, tests=(), driv
|
|||
import frappe.test_runner
|
||||
from frappe.utils import sel
|
||||
|
||||
sel.start(verbose, driver)
|
||||
#sel.start(verbose, driver)
|
||||
|
||||
ret = 1
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -5,31 +5,66 @@ from __future__ import unicode_literals
|
|||
import frappe
|
||||
import json
|
||||
import urllib
|
||||
from email.utils import formataddr
|
||||
from frappe.website.utils import is_signup_enabled
|
||||
from frappe.utils import get_url, cstr, cint, scrub_urls
|
||||
from frappe.email.email_body import get_email
|
||||
from frappe.email.smtp import send
|
||||
import frappe.email.smtp
|
||||
from frappe import _
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
class Communication(Document):
|
||||
def validate(self):
|
||||
if not self.parentfield:
|
||||
self.parentfield = "communications"
|
||||
if not self.sender:
|
||||
self.sender = frappe.db.get_value("User", frappe.session.user, "email")
|
||||
|
||||
def get_parent_doc(self):
|
||||
return frappe.get_doc(self.parenttype, self.parent)
|
||||
|
||||
def update_parent(self):
|
||||
"""update status of parent Lead or Contact based on who is replying"""
|
||||
parent_doc = self.get_parent_doc()
|
||||
parent_doc.run_method("on_communication")
|
||||
if not hasattr(self, "parent_doc"):
|
||||
if self.reference_doctype and self.reference_name:
|
||||
self.parent_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||
else:
|
||||
self.parent_doc = None
|
||||
return self.parent_doc
|
||||
|
||||
def on_update(self):
|
||||
self.update_parent()
|
||||
|
||||
def update_parent(self):
|
||||
"""update status of parent Lead or Contact based on who is replying"""
|
||||
parent = self.get_parent_doc()
|
||||
if not parent:
|
||||
return
|
||||
|
||||
status_field = parent.meta.get_field("status")
|
||||
|
||||
if status_field and "Open" in (status_field.options or "").split("\n"):
|
||||
frappe.db.set_value(parent.doctype, parent.name, "status",
|
||||
"Open" if self.sent_or_received=="Received" else "Replied")
|
||||
|
||||
def send(self, send_me_a_copy=False, print_html=None, print_format=None,
|
||||
attachments=None):
|
||||
mail = get_email(self.recipients, sender=self.sender, subject=self.subject,
|
||||
content=self.content)
|
||||
|
||||
mail.set_message_id(self.name)
|
||||
|
||||
if send_me_a_copy:
|
||||
mail.cc.append(frappe.db.get_value("User", frappe.session.user, "email"))
|
||||
|
||||
if print_html or print_format:
|
||||
attach_print(mail, self.get_parent_doc(), print_html, print_format)
|
||||
|
||||
if isinstance(attachments, basestring):
|
||||
attachments = json.loads(attachments)
|
||||
|
||||
for a in attachments:
|
||||
try:
|
||||
mail.attach_file(a)
|
||||
except IOError:
|
||||
frappe.throw(_("Unable to find attachment {0}").format(a))
|
||||
|
||||
frappe.email.smtp.send(mail)
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Communication", ["reference_doctype", "reference_name"])
|
||||
|
||||
|
|
@ -42,112 +77,24 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received =
|
|||
raise frappe.PermissionError("You are not allowed to send emails related to: {doctype} {name}".format(
|
||||
doctype=doctype, name=name))
|
||||
|
||||
_make(doctype=doctype, name=name, content=content, subject=subject, sent_or_received=sent_or_received,
|
||||
sender=sender, recipients=recipients, communication_medium=communication_medium, send_email=send_email,
|
||||
print_html=print_html, print_format=print_format, attachments=attachments, send_me_a_copy=send_me_a_copy, set_lead=set_lead,
|
||||
date=date)
|
||||
|
||||
def _make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent",
|
||||
sender=None, recipients=None, communication_medium="Email", send_email=False,
|
||||
print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, set_lead=True, date=None):
|
||||
|
||||
# add to Communication
|
||||
sent_via = None
|
||||
|
||||
# since we are using fullname and email,
|
||||
# if the fullname has any incompatible characters,formataddr can deal with it
|
||||
try:
|
||||
sender = json.loads(sender)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if isinstance(sender, (tuple, list)) and len(sender)==2:
|
||||
sender = formataddr(sender)
|
||||
|
||||
comm = frappe.new_doc('Communication')
|
||||
d = comm
|
||||
d.subject = subject
|
||||
d.content = content
|
||||
d.sent_or_received = sent_or_received
|
||||
d.sender = sender or frappe.db.get_value("User", frappe.session.user, "email")
|
||||
d.recipients = recipients
|
||||
|
||||
# add as child
|
||||
sent_via = frappe.get_doc(doctype, name)
|
||||
d.parent = name
|
||||
d.parenttype = doctype
|
||||
d.parentfield = "communications"
|
||||
|
||||
if date:
|
||||
d.communication_date = date
|
||||
|
||||
d.communication_medium = communication_medium
|
||||
|
||||
d.idx = cint(frappe.db.sql("""select max(idx) from `tabCommunication`
|
||||
where parenttype=%s and parent=%s""", (doctype, name))[0][0]) + 1
|
||||
|
||||
comm.ignore_permissions = True
|
||||
comm.insert()
|
||||
comm = frappe.get_doc({
|
||||
"doctype":"Communication",
|
||||
"subject": subject,
|
||||
"content": content,
|
||||
"sender": sender,
|
||||
"recipients": recipients,
|
||||
"communication_medium": "Email",
|
||||
"sent_or_received": sent_or_received,
|
||||
})
|
||||
comm.insert(ignore_permissions=True)
|
||||
|
||||
if send_email:
|
||||
d = comm
|
||||
send_comm_email(d, name, sent_via, print_html, print_format, attachments, send_me_a_copy)
|
||||
comm.send(send_me_a_copy, print_html, print_format, attachments)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_customer_supplier(args=None):
|
||||
"""
|
||||
Get Customer/Supplier, given a contact, if a unique match exists
|
||||
"""
|
||||
if not args: args = frappe.local.form_dict
|
||||
if not args.get('contact'):
|
||||
raise Exception, "Please specify a contact to fetch Customer/Supplier"
|
||||
result = frappe.db.sql("""\
|
||||
select customer, supplier
|
||||
from `tabContact`
|
||||
where name = %s""", args.get('contact'), as_dict=1)
|
||||
if result and len(result)==1 and (result[0]['customer'] or result[0]['supplier']):
|
||||
return {
|
||||
'fieldname': result[0]['customer'] and 'customer' or 'supplier',
|
||||
'value': result[0]['customer'] or result[0]['supplier']
|
||||
}
|
||||
return {}
|
||||
|
||||
def send_comm_email(d, name, sent_via=None, print_html=None, print_format=None, attachments='[]', send_me_a_copy=False):
|
||||
footer = None
|
||||
|
||||
if sent_via:
|
||||
if hasattr(sent_via, "get_sender"):
|
||||
d.sender = sent_via.get_sender(d) or d.sender
|
||||
if hasattr(sent_via, "get_subject"):
|
||||
d.subject = sent_via.get_subject(d)
|
||||
if hasattr(sent_via, "get_content"):
|
||||
d.content = sent_via.get_content(d)
|
||||
|
||||
footer = "<hr>" + set_portal_link(sent_via, d)
|
||||
|
||||
mail = get_email(d.recipients, sender=d.sender, subject=d.subject,
|
||||
msg=d.content, footer=footer)
|
||||
|
||||
mail.set_message_id(d.name)
|
||||
|
||||
if send_me_a_copy:
|
||||
mail.cc.append(frappe.db.get_value("User", frappe.session.user, "email"))
|
||||
|
||||
if print_html or print_format:
|
||||
attach_print(mail, sent_via, print_html, print_format)
|
||||
|
||||
for a in json.loads(attachments):
|
||||
try:
|
||||
mail.attach_file(a)
|
||||
except IOError:
|
||||
frappe.throw(_("Unable to find attachment {0}").format(a))
|
||||
|
||||
send(mail)
|
||||
|
||||
def attach_print(mail, sent_via, print_html, print_format):
|
||||
name = sent_via.name
|
||||
if not print_html and print_format:
|
||||
print_html = frappe.get_print_format(sent_via.doctype, sent_via.name, print_format)
|
||||
def attach_print(mail, parent_doc, print_html, print_format):
|
||||
name = parent_doc.name if parent_doc else "attachment"
|
||||
if (not print_html) and parent_doc and print_format:
|
||||
print_html = frappe.get_print_format(parent_doc.doctype, parent_doc.name, print_format)
|
||||
|
||||
print_settings = frappe.db.get_singles_dict("Print Settings")
|
||||
send_print_as_pdf = cint(print_settings.send_print_as_pdf)
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ import frappe
|
|||
from frappe.email.email_body import get_email
|
||||
from frappe.email.smtp import send
|
||||
|
||||
def sendmail_md(recipients, sender=None, msg=None, subject=None, attachments=None):
|
||||
def sendmail_md(recipients, sender=None, msg=None, subject=None, attachments=None, content=None):
|
||||
"""send markdown email"""
|
||||
import markdown2
|
||||
sendmail(recipients, sender, markdown2.markdown(msg), subject, attachments)
|
||||
sendmail(recipients, sender, markdown2.markdown(content or msg), subject, attachments)
|
||||
|
||||
def sendmail(recipients, sender='', msg='', subject='[No Subject]', attachments=None):
|
||||
def sendmail(recipients, sender='', msg='', subject='[No Subject]', attachments=None, content=None):
|
||||
"""send an html email as multipart with attachments and all"""
|
||||
send(get_email(recipients, sender, msg, subject, attachments=attachments))
|
||||
send(get_email(recipients, sender, content or msg, subject, attachments=attachments))
|
||||
|
||||
def sendmail_to_system_managers(subject, content):
|
||||
send(get_email(get_system_managers(), None, content, subject))
|
||||
|
|
@ -34,7 +34,6 @@ def get_contact_list():
|
|||
|
||||
def get_system_managers():
|
||||
return frappe.db.sql_list("""select parent FROM tabUserRole
|
||||
WHERE role='System Manager'
|
||||
AND parent!='Administrator'
|
||||
AND parent IN
|
||||
(SELECT email FROM tabUser WHERE enabled=1)""")
|
||||
WHERE role='System Manager'
|
||||
AND parent!='Administrator'
|
||||
AND parent IN (SELECT email FROM tabUser WHERE enabled=1)""")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import frappe
|
|||
import HTMLParser
|
||||
import urllib
|
||||
from frappe import msgprint, throw, _
|
||||
from frappe.email.smtp import SMTPServer
|
||||
from frappe.email.smtp import SMTPServer, get_outgoing_email_account
|
||||
from frappe.email.email_body import get_email, get_formatted_html
|
||||
from frappe.email.html2text import html2text
|
||||
from frappe.utils import cint, get_url, nowdate
|
||||
|
|
@ -57,7 +57,7 @@ def send(recipients=None, sender=None, doctype='User', email_field='email',
|
|||
|
||||
if not recipients: recipients = []
|
||||
if not sender or sender == "Administrator":
|
||||
sender = frappe.db.get_value('Outgoing Email Settings', None, 'auto_email_id')
|
||||
sender = get_outgoing_email_account().email_id
|
||||
check_bulk_limit(len(recipients))
|
||||
|
||||
formatted = get_formatted_html(subject, message)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
},
|
||||
{
|
||||
"description": "Check this if this is a global email id like \"sales@yourcompany.com\"",
|
||||
"fieldname": "global",
|
||||
"fieldname": "is_global",
|
||||
"fieldtype": "Check",
|
||||
"label": "Global",
|
||||
"permlevel": 0,
|
||||
|
|
@ -62,15 +62,15 @@
|
|||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"default": "1",
|
||||
"default": "",
|
||||
"description": "Check this to pull emails from your mailbox",
|
||||
"fieldname": "enabled",
|
||||
"fieldname": "enable_incoming",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Enabled",
|
||||
"label": "Enable Incoming",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
|
|
@ -151,20 +151,20 @@
|
|||
{
|
||||
"allow_on_submit": 0,
|
||||
"description": "e.g. pop.gmail.com",
|
||||
"fieldname": "pop3_mail_server",
|
||||
"fieldname": "pop3_server",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "POP3 Mail Server",
|
||||
"label": "POP3 Server",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
|
|
@ -204,6 +204,7 @@
|
|||
"precision": ""
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "enable_outgoing",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Outgoing",
|
||||
|
|
@ -337,6 +338,20 @@
|
|||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "set_footer",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Set Footer",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "footer",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Footer",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
|
|
@ -347,7 +362,7 @@
|
|||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2014-09-11 15:42:06.931247",
|
||||
"modified": "2014-09-15 12:01:38.649639",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Account",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe, os
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import validate_email_add, cint
|
||||
|
|
@ -10,24 +10,37 @@ from frappe.email.smtp import SMTPServer
|
|||
from frappe.email.receive import POP3Server, Email
|
||||
|
||||
class EmailAccount(Document):
|
||||
def autoname(self):
|
||||
if not self.email_account_name:
|
||||
self.email_account_name = self.email_id.split("@", 1)[0]\
|
||||
.replace("_", " ").replace(".", " ").replace("-", " ").title()
|
||||
|
||||
if self.service:
|
||||
self.email_account_name = self.email_account_name + " " + self.service
|
||||
|
||||
self.name = self.email_account_name
|
||||
|
||||
def validate(self):
|
||||
if self.email_id and not validate_email_add(self.email_id):
|
||||
frappe.throw(_("{0} is not a valid email id").format(self.email_id),
|
||||
frappe.InvalidEmailAddressError)
|
||||
|
||||
self.there_must_be_atleast_one_default()
|
||||
self.check_smtp()
|
||||
self.append_to_must_have_subject_and_status()
|
||||
|
||||
if self.enabled:
|
||||
if frappe.local.flags.in_patch or frappe.local.flags.in_test:
|
||||
return
|
||||
|
||||
if self.enable_incoming:
|
||||
self.get_pop3()
|
||||
|
||||
self.check_smtp()
|
||||
|
||||
def on_update(self):
|
||||
self.there_must_be_only_one_default()
|
||||
|
||||
def there_must_be_atleast_one_default(self):
|
||||
if not frappe.db.get_value("Email Account", {"is_default": 1}):
|
||||
if not self.is_default:
|
||||
if not self.is_default and (self.is_global and self.enable_outgoing):
|
||||
self.is_default = 1
|
||||
frappe.msgprint(_("Setting as Default"))
|
||||
|
||||
|
|
@ -42,15 +55,13 @@ class EmailAccount(Document):
|
|||
email_account.is_default = 0
|
||||
email_account.save()
|
||||
|
||||
def append_to_must_have_subject_and_status(self):
|
||||
if self.append_to:
|
||||
meta = frappe.get_meta(self.append_to)
|
||||
if not (meta.has_field("subject") and meta.has_field("status")):
|
||||
frappe.throw(_("Append To DocType must have fields 'Subject' and 'Status'"))
|
||||
|
||||
def check_smtp(self):
|
||||
if self.enable_outgoing and self.smtp_server \
|
||||
and not frappe.local.flags.in_patch:
|
||||
|
||||
if not self.smtp_server:
|
||||
frappe.throw(_("{0} is required").format("SMTP Server"))
|
||||
|
||||
SMTPServer(login = self.email_id,
|
||||
password = self.password,
|
||||
server = self.smtp_server,
|
||||
|
|
@ -60,20 +71,26 @@ class EmailAccount(Document):
|
|||
|
||||
def get_pop3(self):
|
||||
args = {
|
||||
"host": self.smtp_server,
|
||||
"host": self.pop3_server,
|
||||
"use_ssl": self.use_ssl,
|
||||
"username": self.email_id,
|
||||
"password": self.password
|
||||
}
|
||||
|
||||
pop3 = POP3Server(args)
|
||||
if not self.pop3_server:
|
||||
frappe.throw(_("{0} is required").format("POP3 Server"))
|
||||
|
||||
pop3 = POP3Server(frappe._dict(args))
|
||||
pop3.connect()
|
||||
return pop3
|
||||
|
||||
def receive(self):
|
||||
if self.enabled:
|
||||
pop3 = self.get_pop3()
|
||||
incoming_mails = pop3.get_messages()
|
||||
if self.enable_incoming:
|
||||
if frappe.local.flags.in_test:
|
||||
incoming_mails = self.get_test_mails()
|
||||
else:
|
||||
pop3 = self.get_pop3()
|
||||
incoming_mails = pop3.get_messages()
|
||||
|
||||
for raw in incoming_mails:
|
||||
email = Email(raw)
|
||||
|
|
@ -85,7 +102,7 @@ class EmailAccount(Document):
|
|||
"sent_or_received": "Received",
|
||||
"sender_full_name": email.from_real_name,
|
||||
"sender": email.from_email,
|
||||
"recipients": email.get("To"),
|
||||
"recipients": email.mail.get("To"),
|
||||
"email_account": self.name
|
||||
})
|
||||
|
||||
|
|
@ -96,8 +113,11 @@ class EmailAccount(Document):
|
|||
# save attachments
|
||||
email.save_attachments_in_doc(communication)
|
||||
|
||||
if self.enable_auto_reply:
|
||||
self.send_auto_reply(communication)
|
||||
|
||||
def set_thread(self, communication, email):
|
||||
in_reply_to = (email.get("In-Reply-To") or "").strip(" <>")
|
||||
in_reply_to = (email.mail.get("In-Reply-To") or "").strip(" <>")
|
||||
parent = None
|
||||
if in_reply_to:
|
||||
if "@" in in_reply_to:
|
||||
|
|
@ -112,11 +132,15 @@ class EmailAccount(Document):
|
|||
parent = frappe.get_doc(parent.reference_doctype,
|
||||
parent.reference_name)
|
||||
|
||||
|
||||
if not parent and self.append_to:
|
||||
# no parent found, but must be tagged
|
||||
# insert parent type doc
|
||||
parent = self.new_doc(self.append_to)
|
||||
parent.subject = email.subject
|
||||
|
||||
if parent.meta.get_field("subject"):
|
||||
parent.subject = email.subject
|
||||
|
||||
parent.ignore_mandatory = True
|
||||
parent.insert(ignore_permissions=True)
|
||||
|
||||
|
|
@ -126,3 +150,23 @@ class EmailAccount(Document):
|
|||
if parent:
|
||||
communication.reference_doctype = parent.doctype
|
||||
communication.reference_name = parent.name
|
||||
|
||||
def send_auto_reply(self, communication):
|
||||
if self.auto_reply_message:
|
||||
frappe.sendmail(recipients = [communication.from_email],
|
||||
sender = self.email_id,
|
||||
subject = _("Re: ") + communication.subject,
|
||||
content = self.auto_reply_message or\
|
||||
frappe.render_template("templates/emails/auto_reply.html", {}),
|
||||
bulk=True)
|
||||
|
||||
def get_test_mails(self):
|
||||
incoming_mails = []
|
||||
with open(os.path.join(os.path.dirname(__file__), "test_mails", "incoming-1.raw"), "r") as f:
|
||||
incoming_mails.append(f.read())
|
||||
|
||||
return incoming_mails
|
||||
|
||||
def sync_emails(self):
|
||||
for email_account in frappe.get_list("Email Account", filters={"enable_incoming": 1}):
|
||||
frappe.tasks.pull_from_email_account.delay(frappe.local.site, email_account.name)
|
||||
|
|
|
|||
|
|
@ -6,5 +6,22 @@ import unittest
|
|||
|
||||
test_records = frappe.get_test_records('Email Account')
|
||||
|
||||
from frappe.core.doctype.communication.communication import make
|
||||
|
||||
class TestEmailAccount(unittest.TestCase):
|
||||
pass
|
||||
def test_incoming(self):
|
||||
frappe.db.sql("delete from tabCommunication where sender='test_sender@example.com'")
|
||||
|
||||
email_account = frappe.get_doc("Email Account", "_Test Email Account 1")
|
||||
email_account.receive()
|
||||
|
||||
comm = frappe.get_doc("Communication", {"sender": "test_sender@example.com"})
|
||||
self.assertTrue("test_receiver@example.com" in comm.recipients)
|
||||
|
||||
def test_outgoing(self):
|
||||
make(subject = "Test", content="test content", recipients="test_receiver@example.com",
|
||||
send_email=True)
|
||||
|
||||
self.assertTrue(frappe.flags.sent_mail)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,18 @@
|
|||
[
|
||||
{
|
||||
"is_default": 1,
|
||||
"is_global": 1,
|
||||
"doctype": "Email Account",
|
||||
"name": "_Test Email Account 1"
|
||||
"email_account_name": "_Test Email Account 1",
|
||||
"enable_outgoing": 1,
|
||||
"smtp_server": "test.example.com",
|
||||
"email_id": "test@example.com",
|
||||
"password": "password",
|
||||
"add_signature": 1,
|
||||
"signature": "\nBest Wishes\nTest Signature",
|
||||
"enable_auto_reply": 1,
|
||||
"auto_reply_message": "",
|
||||
"enable_incoming": 1,
|
||||
"pop3_server": "pop.test.example.com"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,111 +0,0 @@
|
|||
{
|
||||
"allow_copy": 1,
|
||||
"creation": "2014-03-03 19:48:01",
|
||||
"description": "Email Settings for Outgoing and Incoming Emails.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enabled",
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Server & Credentials",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "SMTP Server (e.g. smtp.gmail.com)",
|
||||
"fieldname": "mail_server",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Outgoing Mail Server",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "<a href=\"https://en.wikipedia.org/wiki/Transport_Layer_Security\" target=\"_blank\">[?]</a>",
|
||||
"fieldname": "use_ssl",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Use TLS",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "If non standard port (e.g. 587)",
|
||||
"fieldname": "mail_port",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Port",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cb0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "Set Login and Password if authentication is required.",
|
||||
"fieldname": "mail_login",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Login Id",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "Check this if you want to send emails as this id only (in case of restriction by your email provider).",
|
||||
"fieldname": "always_use_login_id_as_sender",
|
||||
"fieldtype": "Check",
|
||||
"label": "Always use above Login Id as sender",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "mail_password",
|
||||
"fieldtype": "Password",
|
||||
"label": "Mail Password",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "System generated mails will be sent from this email id.",
|
||||
"fieldname": "auto_email_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Auto Email Id",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_15",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Email Footer",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"default": "<div style=\"padding: 7px; text-align: right; color: #888\"><small>Sent via \n\t<a style=\"color: #888\" href=\"http://frappe.io\">Frappe</a></div>",
|
||||
"fieldname": "footer",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2014-07-17 08:08:00.483392",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Outgoing Email Settings",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"write": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, throw
|
||||
from frappe.utils import validate_email_add
|
||||
from frappe.model.document import Document
|
||||
|
||||
class OutgoingEmailSettings(Document):
|
||||
|
||||
def validate(self):
|
||||
if self.auto_email_id and not validate_email_add(self.auto_email_id):
|
||||
throw(_("{0} is not a valid email id").format(self.auto_email_id), frappe.InvalidEmailAddressError)
|
||||
|
||||
if self.mail_server and not frappe.local.flags.in_patch:
|
||||
from frappe.utils import cint
|
||||
from frappe.email.smtp import SMTPServer
|
||||
smtpserver = SMTPServer(login = self.mail_login,
|
||||
password = self.mail_password,
|
||||
server = self.mail_server,
|
||||
port = cint(self.mail_port),
|
||||
use_ssl = cint(self.use_ssl)
|
||||
)
|
||||
|
||||
# exceptions are handled in session connect
|
||||
sess = smtpserver.sess
|
||||
|
||||
def get_mail_footer():
|
||||
return frappe.db.get_value("Outgoing Email Settings", "Outgoing Email Settings", "footer") or ""
|
||||
|
|
@ -3,19 +3,20 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import msgprint, throw, _
|
||||
from frappe.utils import scrub_urls, get_url
|
||||
from frappe import throw, _
|
||||
from frappe.utils.pdf import get_pdf
|
||||
from frappe.email.smtp import get_outgoing_email_account
|
||||
from frappe.utils import get_url, scrub_urls
|
||||
import email.utils
|
||||
from markdown2 import markdown
|
||||
|
||||
|
||||
def get_email(recipients, sender='', msg='', subject='[No Subject]',
|
||||
text_content = None, footer=None, print_html=None, formatted=None, attachments=None):
|
||||
text_content = None, footer=None, print_html=None, formatted=None, attachments=None,
|
||||
content=None):
|
||||
"""send an html email as multipart with attachments and all"""
|
||||
emailobj = EMail(sender, recipients, subject)
|
||||
msg = markdown(msg)
|
||||
emailobj.set_html(msg, text_content, footer=footer, print_html=print_html, formatted=formatted)
|
||||
msg = markdown(content or msg)
|
||||
emailobj.set_html(content or msg, text_content, footer=footer, print_html=print_html, formatted=formatted)
|
||||
|
||||
if isinstance(attachments, dict):
|
||||
attachments = [attachments]
|
||||
|
|
@ -166,14 +167,7 @@ class EMail:
|
|||
return email
|
||||
|
||||
if not self.sender:
|
||||
self.sender = frappe.db.get_value('Outgoing Email Settings', None,
|
||||
'auto_email_id') or frappe.conf.get('auto_email_id') or None
|
||||
if not self.sender:
|
||||
msg = _("Please specify 'Auto Email Id' in Setup > Outgoing Email Settings")
|
||||
msgprint(msg)
|
||||
if not "expires_on" in frappe.conf:
|
||||
msgprint(_("Alternatively, you can also specify 'auto_email_id' in site_config.json"))
|
||||
raise frappe.ValidationError, msg
|
||||
self.sender = get_outgoing_email_account().email_id
|
||||
|
||||
self.sender = _validate(self.sender)
|
||||
self.reply_to = _validate(self.reply_to)
|
||||
|
|
@ -223,11 +217,16 @@ def get_footer(footer=None):
|
|||
"""append a footer (signature)"""
|
||||
footer = footer or ""
|
||||
|
||||
# hooks
|
||||
for f in frappe.get_hooks("mail_footer"):
|
||||
# mail_footer could be a function that returns a value
|
||||
mail_footer = frappe.get_attr(f)
|
||||
footer += (mail_footer if isinstance(mail_footer, basestring) else mail_footer())
|
||||
email_account = get_outgoing_email_account()
|
||||
|
||||
if email_account.add_signature and email_account.signature:
|
||||
footer += email_account.signature
|
||||
|
||||
if email_account.footer:
|
||||
footer += email_account.footer
|
||||
else:
|
||||
for default_mail_footer in frappe.get_hooks("default_mail_footer"):
|
||||
footer += default_mail_footer
|
||||
|
||||
footer += "<!--unsubscribe link here-->"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
import time
|
||||
import poplib
|
||||
import _socket, poplib
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import extract_email_id, convert_utc_to_user_timezone, now, cint
|
||||
from frappe.utils.scheduler import log
|
||||
|
||||
|
|
@ -37,11 +38,11 @@ class POP3Server:
|
|||
|
||||
self.pop.user(self.settings.username)
|
||||
self.pop.pass_(self.settings.password)
|
||||
except _socket.error, e:
|
||||
except _socket.error:
|
||||
# Invalid mail server -- due to refusing connection
|
||||
frappe.msgprint(_('Invalid Mail Server. Please rectify and try again.'))
|
||||
raise
|
||||
except poplib.error_proto, e:
|
||||
except poplib.error_proto:
|
||||
frappe.msgprint(_('Invalid User Name or Support Password. Please rectify and try again.'))
|
||||
raise
|
||||
|
||||
|
|
@ -132,7 +133,7 @@ class POP3Server:
|
|||
if not incoming_mail:
|
||||
try:
|
||||
# retrieve headers
|
||||
incoming_mail = EMail(b'\n'.join(self.pop.top(msg_num, 5)[1]))
|
||||
incoming_mail = Email(b'\n'.join(self.pop.top(msg_num, 5)[1]))
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
@ -232,7 +233,7 @@ class Email:
|
|||
from frappe.utils.file_manager import save_file, MaxFileSizeReachedError
|
||||
for attachment in self.attachments:
|
||||
try:
|
||||
fid = save_file(attachment['filename'], attachment['content'],
|
||||
save_file(attachment['filename'], attachment['content'],
|
||||
doc.doctype, doc.name)
|
||||
except MaxFileSizeReachedError:
|
||||
# WARNING: bypass max file size exception
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ def send(email, as_bulk=False):
|
|||
frappe.msgprint(_("Emails are muted"))
|
||||
return
|
||||
|
||||
if frappe.flags.in_test:
|
||||
frappe.flags.sent_mail = email.as_string()
|
||||
return
|
||||
|
||||
try:
|
||||
smtpserver = SMTPServer()
|
||||
if hasattr(smtpserver, "always_use_login_id_as_sender") and \
|
||||
|
|
@ -33,34 +37,57 @@ def send(email, as_bulk=False):
|
|||
frappe.msgprint(_("Invalid recipient address"))
|
||||
raise
|
||||
|
||||
def get_outgoing_email_account(raise_exception_not_set=True):
|
||||
if not getattr(frappe.local, "outgoing_email_account", None):
|
||||
email_account = frappe.db.get_value("Email Account", {
|
||||
"owner": frappe.session.user, "enable_outgoing": 1})
|
||||
|
||||
if not email_account:
|
||||
email_account = frappe.db.get_value('Email Account', {"is_default": 1})
|
||||
|
||||
if not email_account and not raise_exception_not_set:
|
||||
return None
|
||||
|
||||
if not email_account:
|
||||
frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"))
|
||||
|
||||
frappe.local.outgoing_email_account = frappe.get_doc("Email Account", email_account)
|
||||
|
||||
return frappe.local.outgoing_email_account
|
||||
|
||||
class SMTPServer:
|
||||
def __init__(self, login=None, password=None, server=None, port=None, use_ssl=None):
|
||||
# get defaults from mail settings
|
||||
try:
|
||||
self.email_settings = frappe.get_doc('Outgoing Email Settings', 'Outgoing Email Settings')
|
||||
except frappe.DoesNotExistError:
|
||||
self.email_settings = None
|
||||
|
||||
self._sess = None
|
||||
self.email_account = None
|
||||
if server:
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.use_ssl = cint(use_ssl)
|
||||
self.login = login
|
||||
self.password = password
|
||||
elif self.email_settings and cint(self.email_settings.enabled):
|
||||
self.server = self.email_settings.mail_server
|
||||
self.port = self.email_settings.mail_port
|
||||
self.use_ssl = cint(self.email_settings.use_ssl)
|
||||
self.login = self.email_settings.mail_login
|
||||
self.password = self.email_settings.mail_password
|
||||
self.always_use_login_id_as_sender = self.email_settings.always_use_login_id_as_sender
|
||||
|
||||
else:
|
||||
self.server = frappe.conf.get("mail_server") or ""
|
||||
self.port = frappe.conf.get("mail_port") or None
|
||||
self.use_ssl = cint(frappe.conf.get("use_ssl") or 0)
|
||||
self.login = frappe.conf.get("mail_login") or ""
|
||||
self.password = frappe.conf.get("mail_password") or ""
|
||||
self.setup_from_user_or_default_outgoing()
|
||||
|
||||
# from config
|
||||
if not self.server:
|
||||
self.server = frappe.conf.get("mail_server") or ""
|
||||
self.port = frappe.conf.get("mail_port") or None
|
||||
self.use_ssl = cint(frappe.conf.get("use_ssl") or 0)
|
||||
self.login = frappe.conf.get("mail_login") or ""
|
||||
self.password = frappe.conf.get("mail_password") or ""
|
||||
|
||||
def setup_from_user_or_default_outgoing(self):
|
||||
self.email_account = get_outgoing_email_account(raise_exception_not_set=False)
|
||||
if self.email_account:
|
||||
self.server = self.email_account.smtp_server
|
||||
self.login = self.email_account.email_id
|
||||
self.password = self.email_account.password
|
||||
self.port = self.email_account.smtp_port
|
||||
self.use_ssl = self.email_account.use_tls
|
||||
|
||||
|
||||
@property
|
||||
def sess(self):
|
||||
|
|
@ -70,7 +97,7 @@ class SMTPServer:
|
|||
|
||||
# check if email server specified
|
||||
if not self.server:
|
||||
err_msg = _('Outgoing Mail Server not specified')
|
||||
err_msg = _('Email Account not setup. Please create a new Email Account from Setup > Email > Email Account')
|
||||
frappe.msgprint(err_msg)
|
||||
raise frappe.OutgoingEmailError, err_msg
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,10 @@ doc_events = {
|
|||
}
|
||||
|
||||
scheduler_events = {
|
||||
"all": ["frappe.email.bulk.flush"],
|
||||
"all": [
|
||||
"frappe.email.bulk.flush",
|
||||
"frappe.tasks.pull_emails"
|
||||
],
|
||||
"daily": [
|
||||
"frappe.email.bulk.clear_outbox",
|
||||
"frappe.core.doctype.notification_count.notification_count.clear_notifications",
|
||||
|
|
@ -95,5 +98,3 @@ scheduler_events = {
|
|||
"frappe.website.doctype.website_group.website_group.clear_event_cache"
|
||||
]
|
||||
}
|
||||
|
||||
mail_footer = "frappe.email.doctype.outgoing_email_settings.outgoing_email_settings.get_mail_footer"
|
||||
|
|
|
|||
|
|
@ -136,8 +136,8 @@ class Document(BaseDocument):
|
|||
self._set_defaults()
|
||||
self._set_docstatus_user_and_timestamp()
|
||||
self.check_if_latest()
|
||||
self.set_new_name()
|
||||
self.run_method("before_insert")
|
||||
self.set_new_name()
|
||||
self.set_parent_in_children()
|
||||
|
||||
self.set("__in_insert", True)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
|||
import frappe
|
||||
|
||||
def execute():
|
||||
return
|
||||
frappe.reload_doc("core", "doctype", "outgoing_email_settings")
|
||||
if (frappe.db.get_value("Outgoing Email Settings", "Outgoing Email Settings", "mail_server") or "").strip():
|
||||
frappe.db.set_value("Outgoing Email Settings", "Outgoing Email Settings", "enabled", 1)
|
||||
|
|
|
|||
|
|
@ -15,12 +15,11 @@ def execute():
|
|||
pass
|
||||
else:
|
||||
# if someone has already configured in Outgoing Email Settings
|
||||
outgoing_email_settings = frappe.db.get_singles_dict("Outgoing Email Settings")
|
||||
if "send_print_as_pdf" in outgoing_email_settings:
|
||||
# outgoing_email_settings = frappe.db.get_singles_dict("Outgoing Email Settings")
|
||||
if False: # "send_print_as_pdf" in outgoing_email_settings:
|
||||
print_settings.send_print_as_pdf = outgoing_email_settings.send_print_as_pdf
|
||||
print_settings.pdf_page_size = outgoing_email_settings.pdf_page_size
|
||||
|
||||
else:
|
||||
print_settings.send_print_as_pdf = 1
|
||||
|
||||
print_settings.save()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ def execute():
|
|||
("desk", ("event", "event_role", "event_user", "todo", "feed",
|
||||
"note", "note_user")),
|
||||
("email", ("bulk_email", "email_alert", "email_alert_recipient",
|
||||
"outgoing_email_settings", "standard_reply")),
|
||||
"standard_reply")),
|
||||
("geo", ("country", "currency")),
|
||||
("print", ("letter_head", "print_format", "print_settings"))
|
||||
)
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ frappe.ui.form.Comments = Class.extend({
|
|||
}
|
||||
|
||||
// icon centering -- pixed perfect
|
||||
if(in_list(["Comment", "Email"], c.comment_type)) {
|
||||
if(in_list(["Comment", "Email", "Assignment Completed"], c.comment_type)) {
|
||||
c.padding = "padding-left: 8px;";
|
||||
} else if(in_list(["Created"], c.comment_type)) {
|
||||
c.padding = "padding-left: 9px;";
|
||||
|
|
|
|||
|
|
@ -108,3 +108,13 @@ def enqueue_events_for_site(site):
|
|||
enqueue_events(site)
|
||||
finally:
|
||||
frappe.destroy()
|
||||
|
||||
@celery_task()
|
||||
def pull_from_email_account(site, email_account):
|
||||
try:
|
||||
frappe.init(site=site)
|
||||
frappe.connect(site=site)
|
||||
email_account = frappe.get_doc("Email Account", email_account)
|
||||
email_account.receive()
|
||||
finally:
|
||||
frappe.destroy()
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ def add_comment(args=None):
|
|||
owner = frappe.db.get_value(comment.comment_doctype, comment.comment_docname, "owner")
|
||||
recipients = list(set(commentors if owner=="Administrator" else (commentors + [owner])))
|
||||
|
||||
|
||||
from frappe.email.bulk import send
|
||||
send(recipients=recipients,
|
||||
doctype='Comment',
|
||||
|
|
|
|||
|
|
@ -115,8 +115,6 @@ def _add_test(path, filename, verbose, test_suite=None):
|
|||
test_suite.addTest(unittest.TestLoader().loadTestsFromModule(module))
|
||||
|
||||
def make_test_records(doctype, verbose=0, force=False):
|
||||
frappe.flags.mute_emails = True
|
||||
|
||||
if not frappe.db:
|
||||
frappe.connect()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue