[rename] Bulk Email to Email Queueversion-14
@@ -7,7 +7,6 @@ globals attached to frappe module | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
from werkzeug.local import Local, release_local | from werkzeug.local import Local, release_local | ||||
from functools import wraps | |||||
import os, importlib, inspect, json | import os, importlib, inspect, json | ||||
# public | # public | ||||
@@ -252,7 +251,7 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, | |||||
:param raise_exception: [optional] Raise given exception and show message. | :param raise_exception: [optional] Raise given exception and show message. | ||||
:param as_table: [optional] If `msg` is a list of lists, render as HTML table. | :param as_table: [optional] If `msg` is a list of lists, render as HTML table. | ||||
""" | """ | ||||
from utils import cstr, encode | |||||
from utils import encode | |||||
out = _dict(message=msg) | out = _dict(message=msg) | ||||
@@ -355,11 +354,11 @@ def get_request_header(key, default=None): | |||||
return request.headers.get(key, default) | return request.headers.get(key, default) | ||||
def sendmail(recipients=(), sender="", subject="No Subject", message="No Message", | def sendmail(recipients=(), sender="", subject="No Subject", message="No Message", | ||||
as_markdown=False, bulk=False, reference_doctype=None, reference_name=None, | |||||
as_markdown=False, delayed=True, reference_doctype=None, reference_name=None, | |||||
unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, | unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, | ||||
attachments=None, content=None, doctype=None, name=None, reply_to=None, | attachments=None, content=None, doctype=None, name=None, reply_to=None, | ||||
cc=(), show_as_cc=(), message_id=None, in_reply_to=None, as_bulk=False, send_after=None, expose_recipients=False, | |||||
bulk_priority=1, communication=None): | |||||
cc=(), show_as_cc=(), message_id=None, in_reply_to=None, send_after=None, expose_recipients=False, | |||||
send_priority=1, communication=None): | |||||
"""Send email using user's default **Email Account** or global default **Email Account**. | """Send email using user's default **Email Account** or global default **Email Account**. | ||||
@@ -368,8 +367,8 @@ def sendmail(recipients=(), sender="", subject="No Subject", message="No Message | |||||
:param subject: Email Subject. | :param subject: Email Subject. | ||||
:param message: (or `content`) Email Content. | :param message: (or `content`) Email Content. | ||||
:param as_markdown: Convert content markdown to HTML. | :param as_markdown: Convert content markdown to HTML. | ||||
:param bulk: Send via scheduled email sender **Bulk Email**. Don't send immediately. | |||||
:param bulk_priority: Priority for bulk email, default 1. | |||||
:param delayed: Send via scheduled email sender **Email Queue**. Don't send immediately. Default is true | |||||
:param send_priority: Priority for Email Queue, default 1. | |||||
:param reference_doctype: (or `doctype`) Append as communication to this DocType. | :param reference_doctype: (or `doctype`) Append as communication to this DocType. | ||||
:param reference_name: (or `name`) Append as communication to this document name. | :param reference_name: (or `name`) Append as communication to this document name. | ||||
:param unsubscribe_method: Unsubscribe url with options email, doctype, name. e.g. `/api/method/unsubscribe` | :param unsubscribe_method: Unsubscribe url with options email, doctype, name. e.g. `/api/method/unsubscribe` | ||||
@@ -380,17 +379,17 @@ def sendmail(recipients=(), sender="", subject="No Subject", message="No Message | |||||
:param in_reply_to: Used to send the Message-Id of a received email back as In-Reply-To. | :param in_reply_to: Used to send the Message-Id of a received email back as In-Reply-To. | ||||
:param send_after: Send after the given datetime. | :param send_after: Send after the given datetime. | ||||
:param expose_recipients: Display all recipients in the footer message - "This email was sent to" | :param expose_recipients: Display all recipients in the footer message - "This email was sent to" | ||||
:param communication: Communication link to be set in Bulk Email record | |||||
:param communication: Communication link to be set in Email Queue record | |||||
""" | """ | ||||
if bulk or as_bulk: | |||||
import frappe.email.bulk | |||||
frappe.email.bulk.send(recipients=recipients, sender=sender, | |||||
if delayed: | |||||
import frappe.email.queue | |||||
frappe.email.queue.send(recipients=recipients, sender=sender, | |||||
subject=subject, message=content or message, | subject=subject, message=content or message, | ||||
reference_doctype = doctype or reference_doctype, reference_name = name or reference_name, | reference_doctype = doctype or reference_doctype, reference_name = name or reference_name, | ||||
unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, unsubscribe_message=unsubscribe_message, | unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, unsubscribe_message=unsubscribe_message, | ||||
attachments=attachments, reply_to=reply_to, cc=cc, show_as_cc=show_as_cc, message_id=message_id, in_reply_to=in_reply_to, | attachments=attachments, reply_to=reply_to, cc=cc, show_as_cc=show_as_cc, message_id=message_id, in_reply_to=in_reply_to, | ||||
send_after=send_after, expose_recipients=expose_recipients, bulk_priority=bulk_priority, communication=communication) | |||||
send_after=send_after, expose_recipients=expose_recipients, send_priority=send_priority, communication=communication) | |||||
else: | else: | ||||
import frappe.email | import frappe.email | ||||
if as_markdown: | if as_markdown: | ||||
@@ -918,7 +917,6 @@ def import_doc(path, ignore_links=False, ignore_insert=False, insert=False): | |||||
def copy_doc(doc, ignore_no_copy=True): | def copy_doc(doc, ignore_no_copy=True): | ||||
""" No_copy fields also get copied.""" | """ No_copy fields also get copied.""" | ||||
import copy | import copy | ||||
from frappe.model import optional_fields, default_fields | |||||
def remove_no_copy_fields(d): | def remove_no_copy_fields(d): | ||||
for df in d.meta.get("fields", {"no_copy": 1}): | for df in d.meta.get("fields", {"no_copy": 1}): | ||||
@@ -146,16 +146,16 @@ def execute(context, method, args=None, kwargs=None): | |||||
print json.dumps(ret) | print json.dumps(ret) | ||||
@click.command('add-bulk-email') | |||||
@click.command('add-to-email-queue') | |||||
@click.argument('email') | @click.argument('email') | ||||
@pass_context | @pass_context | ||||
def add_bulk_email(context, email): | |||||
"Add an email to the Bulk Email queue" | |||||
def add_to_email_queue(context, email): | |||||
"Add an email to the Email Queue" | |||||
site = get_site(context) | site = get_site(context) | ||||
with frappe.init_site(site): | with frappe.init_site(site): | ||||
frappe.connect() | frappe.connect() | ||||
kwargs = json.loads(email) | kwargs = json.loads(email) | ||||
kwargs['as_bulk'] = True | |||||
kwargs['delayed'] = True | |||||
frappe.sendmail(**kwargs) | frappe.sendmail(**kwargs) | ||||
frappe.db.commit() | frappe.db.commit() | ||||
@@ -408,7 +408,6 @@ def get_version(): | |||||
print "{0} {1}".format(m, module.__version__) | print "{0} {1}".format(m, module.__version__) | ||||
commands = [ | commands = [ | ||||
add_bulk_email, | |||||
build, | build, | ||||
build_website, | build_website, | ||||
clear_cache, | clear_cache, | ||||
@@ -433,4 +432,5 @@ commands = [ | |||||
sync_www, | sync_www, | ||||
watch, | watch, | ||||
_bulk_rename, | _bulk_rename, | ||||
add_to_email_queue, | |||||
] | ] |
@@ -48,7 +48,7 @@ def get_data(): | |||||
}, | }, | ||||
{ | { | ||||
"type": "doctype", | "type": "doctype", | ||||
"name": "Bulk Email", | |||||
"name": "Email Queue", | |||||
"description": _("Background Email Queue"), | "description": _("Background Email Queue"), | ||||
}, | }, | ||||
{ | { | ||||
@@ -104,8 +104,7 @@ def notify_mentions(doc): | |||||
recipients=recipients, | recipients=recipients, | ||||
sender=frappe.session.user, | sender=frappe.session.user, | ||||
subject=subject, | subject=subject, | ||||
message=message, | |||||
bulk=True | |||||
message=message | |||||
) | ) | ||||
def get_comments_from_parent(doc): | def get_comments_from_parent(doc): | ||||
@@ -161,7 +161,7 @@ class Communication(Document): | |||||
def notify(self, print_html=None, print_format=None, attachments=None, | def notify(self, print_html=None, print_format=None, attachments=None, | ||||
recipients=None, cc=None, fetched_from_email_account=False): | recipients=None, cc=None, fetched_from_email_account=False): | ||||
"""Calls a delayed task 'sendmail' that enqueus email in Bulk Email queue | |||||
"""Calls a delayed task 'sendmail' that enqueus email in Email Queue queue | |||||
:param print_html: Send given value as HTML attachment | :param print_html: Send given value as HTML attachment | ||||
:param print_format: Attach print format of parent document | :param print_format: Attach print format of parent document | ||||
@@ -193,9 +193,9 @@ class Communication(Document): | |||||
frappe.local.flags.commit = True | frappe.local.flags.commit = True | ||||
def set_delivery_status(self, commit=False): | def set_delivery_status(self, commit=False): | ||||
'''Look into the status of Bulk Email linked to this Communication and set the Delivery Status of this Communication''' | |||||
'''Look into the status of Email Queue linked to this Communication and set the Delivery Status of this Communication''' | |||||
delivery_status = None | delivery_status = None | ||||
status_counts = Counter(frappe.db.sql_list('''select status from `tabBulk Email` where communication=%s''', self.name)) | |||||
status_counts = Counter(frappe.db.sql_list('''select status from `tabEmail Queue` where communication=%s''', self.name)) | |||||
if status_counts.get('Not Sent') or status_counts.get('Sending'): | if status_counts.get('Not Sent') or status_counts.get('Sending'): | ||||
delivery_status = 'Sending' | delivery_status = 'Sending' | ||||
@@ -8,7 +8,7 @@ from email.utils import formataddr, parseaddr | |||||
from frappe.utils import (get_url, get_formatted_email, cint, | from frappe.utils import (get_url, get_formatted_email, cint, | ||||
validate_email_add, split_emails, time_diff_in_seconds) | validate_email_add, split_emails, time_diff_in_seconds) | ||||
from frappe.utils.file_manager import get_file | from frappe.utils.file_manager import get_file | ||||
from frappe.email.bulk import check_bulk_limit | |||||
from frappe.email.queue import check_email_limit | |||||
from frappe.utils.scheduler import log | from frappe.utils.scheduler import log | ||||
import frappe.email.smtp | import frappe.email.smtp | ||||
import MySQLdb | import MySQLdb | ||||
@@ -89,7 +89,7 @@ def validate_email(doc): | |||||
def notify(doc, print_html=None, print_format=None, attachments=None, | def notify(doc, print_html=None, print_format=None, attachments=None, | ||||
recipients=None, cc=None, fetched_from_email_account=False): | recipients=None, cc=None, fetched_from_email_account=False): | ||||
"""Calls a delayed task 'sendmail' that enqueus email in Bulk Email queue | |||||
"""Calls a delayed task 'sendmail' that enqueus email in Email Queue queue | |||||
:param print_html: Send given value as HTML attachment | :param print_html: Send given value as HTML attachment | ||||
:param print_format: Attach print format of parent document | :param print_format: Attach print format of parent document | ||||
@@ -109,7 +109,7 @@ def notify(doc, print_html=None, print_format=None, attachments=None, | |||||
doc._notify(print_html=print_html, print_format=print_format, attachments=attachments, | doc._notify(print_html=print_html, print_format=print_format, attachments=attachments, | ||||
recipients=recipients, cc=cc) | recipients=recipients, cc=cc) | ||||
else: | else: | ||||
check_bulk_limit(list(set(doc.sent_email_addresses))) | |||||
check_email_limit(list(set(doc.sent_email_addresses))) | |||||
enqueue(sendmail, queue="default", timeout=300, event="sendmail", | enqueue(sendmail, queue="default", timeout=300, event="sendmail", | ||||
communication_name=doc.name, | communication_name=doc.name, | ||||
print_html=print_html, print_format=print_format, attachments=attachments, | print_html=print_html, print_format=print_format, attachments=attachments, | ||||
@@ -133,7 +133,7 @@ def _notify(doc, print_html=None, print_format=None, attachments=None, | |||||
attachments=doc.attachments, | attachments=doc.attachments, | ||||
message_id=doc.name, | message_id=doc.name, | ||||
unsubscribe_message=_("Leave this conversation"), | unsubscribe_message=_("Leave this conversation"), | ||||
bulk=True, | |||||
delayed=True, | |||||
communication=doc.name | communication=doc.name | ||||
) | ) | ||||
@@ -191,7 +191,7 @@ def prepare_to_notify(doc, print_html=None, print_format=None, attachments=None) | |||||
:param print_html: Send given value as HTML attachment. | :param print_html: Send given value as HTML attachment. | ||||
:param print_format: Attach print format of parent document.""" | :param print_format: Attach print format of parent document.""" | ||||
view_link = frappe.utils.cint(frappe.db.get_value("Print Settings", "Print Settings", "attach_view_link")) | view_link = frappe.utils.cint(frappe.db.get_value("Print Settings", "Print Settings", "attach_view_link")) | ||||
if print_format and view_link: | if print_format and view_link: | ||||
@@ -189,19 +189,21 @@ class User(Document): | |||||
(self.first_name and " " or '') + (self.last_name or '') | (self.first_name and " " or '') + (self.last_name or '') | ||||
def password_reset_mail(self, link): | def password_reset_mail(self, link): | ||||
self.send_login_mail(_("Password Reset"), "templates/emails/password_reset.html", {"link": link}) | |||||
self.send_login_mail(_("Password Reset"), | |||||
"templates/emails/password_reset.html", {"link": link}, now=True) | |||||
def password_update_mail(self, password): | def password_update_mail(self, password): | ||||
self.send_login_mail(_("Password Update"), "templates/emails/password_update.html", {"new_password": password}) | |||||
self.send_login_mail(_("Password Update"), | |||||
"templates/emails/password_update.html", {"new_password": password}, now=True) | |||||
def send_welcome_mail_to_user(self): | def send_welcome_mail_to_user(self): | ||||
from frappe.utils import random_string, get_url | |||||
from frappe.utils import get_url | |||||
link = self.reset_password() | link = self.reset_password() | ||||
self.send_login_mail(_("Verify Your Account"), "templates/emails/new_user.html", | self.send_login_mail(_("Verify Your Account"), "templates/emails/new_user.html", | ||||
{"link": link, "site_url": get_url()}) | {"link": link, "site_url": get_url()}) | ||||
def send_login_mail(self, subject, template, add_args): | |||||
def send_login_mail(self, subject, template, add_args, now=None): | |||||
"""send mail with login details""" | """send mail with login details""" | ||||
from frappe.utils.user import get_user_fullname | from frappe.utils.user import get_user_fullname | ||||
from frappe.utils import get_url | from frappe.utils import get_url | ||||
@@ -226,7 +228,8 @@ class User(Document): | |||||
sender = frappe.session.user not in STANDARD_USERS and get_formatted_email(frappe.session.user) or None | sender = frappe.session.user not in STANDARD_USERS and get_formatted_email(frappe.session.user) or None | ||||
frappe.sendmail(recipients=self.email, sender=sender, subject=subject, | frappe.sendmail(recipients=self.email, sender=sender, subject=subject, | ||||
message=frappe.get_template(template).render(args), as_bulk=self.flags.delay_emails) | |||||
message=frappe.get_template(template).render(args), | |||||
delayed=now if now!=None else self.flags.delay_emails) | |||||
def a_system_manager_should_exist(self): | def a_system_manager_should_exist(self): | ||||
if not self.get_other_system_managers(): | if not self.get_other_system_managers(): | ||||
@@ -607,7 +610,7 @@ def notifify_admin_access_to_system_manager(login_manager=None): | |||||
) | ) | ||||
frappe.sendmail(recipients=get_system_managers(), subject=_("Administrator Logged In"), | frappe.sendmail(recipients=get_system_managers(), subject=_("Administrator Logged In"), | ||||
message=message, bulk=True) | |||||
message=message) | |||||
def extract_mentions(txt): | def extract_mentions(txt): | ||||
"""Find all instances of @username in the string. | """Find all instances of @username in the string. | ||||
@@ -66,7 +66,7 @@ def send_event_digest(): | |||||
+ frappe._("Daily Event Digest is sent for Calendar Events where reminders are set.")+'</p>' | + frappe._("Daily Event Digest is sent for Calendar Events where reminders are set.")+'</p>' | ||||
frappe.sendmail(recipients=user.email, subject=frappe._("Upcoming Events for Today"), | frappe.sendmail(recipients=user.email, subject=frappe._("Upcoming Events for Today"), | ||||
content = text, bulk=True) | |||||
content = text) | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def get_events(start, end, user=None, for_reminder=False): | def get_events(start, end, user=None, for_reminder=False): | ||||
@@ -131,7 +131,6 @@ def _notify(contact, txt, subject=None): | |||||
"from": get_fullname(frappe.session.user), | "from": get_fullname(frappe.session.user), | ||||
"message": txt, | "message": txt, | ||||
"link": get_url() | "link": get_url() | ||||
}), | |||||
bulk=True) | |||||
})) | |||||
except frappe.OutgoingEmailError: | except frappe.OutgoingEmailError: | ||||
pass | pass |
@@ -1 +0,0 @@ | |||||
Emails to be sent asynchronously via the scheduler. Emails remain in Bulk Email for a month before they are deleted (to check mail quotas) |
@@ -1,4 +0,0 @@ | |||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals |
@@ -1,307 +0,0 @@ | |||||
{ | |||||
"allow_copy": 0, | |||||
"allow_import": 0, | |||||
"allow_rename": 0, | |||||
"autoname": "hash", | |||||
"beta": 0, | |||||
"creation": "2012-08-02 15:17:28", | |||||
"custom": 0, | |||||
"description": "Bulk Email records.", | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "System", | |||||
"fields": [ | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "sender", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Sender", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Email", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "recipient", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 1, | |||||
"label": "Recipient", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Email", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "message", | |||||
"fieldtype": "Code", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Message", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"default": "Not Sent", | |||||
"fieldname": "status", | |||||
"fieldtype": "Select", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 1, | |||||
"label": "Status", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "\nNot Sent\nSending\nSent\nError\nExpired", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "error", | |||||
"fieldtype": "Code", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Error", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "reference_doctype", | |||||
"fieldtype": "Link", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Reference DocType", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "DocType", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "reference_name", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Reference DocName", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "communication", | |||||
"fieldtype": "Link", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Communication", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Communication", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 1, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "send_after", | |||||
"fieldtype": "Datetime", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Send After", | |||||
"length": 0, | |||||
"no_copy": 1, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"default": "1", | |||||
"fieldname": "priority", | |||||
"fieldtype": "Int", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Priority", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
} | |||||
], | |||||
"hide_heading": 0, | |||||
"hide_toolbar": 0, | |||||
"icon": "icon-envelope", | |||||
"idx": 1, | |||||
"in_create": 1, | |||||
"in_dialog": 0, | |||||
"is_submittable": 0, | |||||
"issingle": 0, | |||||
"istable": 0, | |||||
"max_attachments": 0, | |||||
"modified": "2016-05-26 06:00:18.596285", | |||||
"modified_by": "Administrator", | |||||
"module": "Email", | |||||
"name": "Bulk Email", | |||||
"owner": "Administrator", | |||||
"permissions": [ | |||||
{ | |||||
"amend": 0, | |||||
"apply_user_permissions": 0, | |||||
"cancel": 0, | |||||
"create": 0, | |||||
"delete": 1, | |||||
"email": 1, | |||||
"export": 0, | |||||
"if_owner": 0, | |||||
"import": 0, | |||||
"permlevel": 0, | |||||
"print": 1, | |||||
"read": 1, | |||||
"report": 1, | |||||
"role": "System Manager", | |||||
"set_user_permissions": 0, | |||||
"share": 0, | |||||
"submit": 0, | |||||
"write": 0 | |||||
} | |||||
], | |||||
"quick_entry": 0, | |||||
"read_only": 0, | |||||
"read_only_onload": 0, | |||||
"sort_order": "DESC", | |||||
"track_seen": 0 | |||||
} |
@@ -1,12 +0,0 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||||
# See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
import unittest | |||||
# test_records = frappe.get_test_records('Bulk Email') | |||||
class TestBulkEmail(unittest.TestCase): | |||||
pass |
@@ -355,8 +355,7 @@ class EmailAccount(Document): | |||||
reference_name = communication.reference_name, | reference_name = communication.reference_name, | ||||
message_id = communication.name, | message_id = communication.name, | ||||
in_reply_to = email.mail.get("Message-Id"), # send back the Message-Id as In-Reply-To | in_reply_to = email.mail.get("Message-Id"), # send back the Message-Id as In-Reply-To | ||||
unsubscribe_message = _("Leave this conversation"), | |||||
bulk=True) | |||||
unsubscribe_message = _("Leave this conversation")) | |||||
def get_unreplied_notification_emails(self): | def get_unreplied_notification_emails(self): | ||||
"""Return list of emails listed""" | """Return list of emails listed""" | ||||
@@ -398,7 +397,7 @@ def notify_unreplied(): | |||||
# if status is still open | # if status is still open | ||||
frappe.sendmail(recipients=email_account.get_unreplied_notification_emails(), | frappe.sendmail(recipients=email_account.get_unreplied_notification_emails(), | ||||
content=comm.content, subject=comm.subject, doctype= comm.reference_doctype, | content=comm.content, subject=comm.subject, doctype= comm.reference_doctype, | ||||
name=comm.reference_name, bulk=True) | |||||
name=comm.reference_name) | |||||
# update flag | # update flag | ||||
comm.db_set("unread_notification_sent", 1) | comm.db_set("unread_notification_sent", 1) | ||||
@@ -42,9 +42,9 @@ class TestEmailAccount(unittest.TestCase): | |||||
comm = frappe.get_doc("Communication", {"sender": "test_sender@example.com"}) | comm = frappe.get_doc("Communication", {"sender": "test_sender@example.com"}) | ||||
comm.db_set("creation", datetime.now() - timedelta(seconds = 30 * 60)) | comm.db_set("creation", datetime.now() - timedelta(seconds = 30 * 60)) | ||||
frappe.db.sql("delete from `tabBulk Email`") | |||||
frappe.db.sql("delete from `tabEmail Queue`") | |||||
notify_unreplied() | notify_unreplied() | ||||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": comm.reference_doctype, | |||||
self.assertTrue(frappe.db.get_value("Email Queue", {"reference_doctype": comm.reference_doctype, | |||||
"reference_name": comm.reference_name, "status":"Not Sent"})) | "reference_name": comm.reference_name, "status":"Not Sent"})) | ||||
def test_incoming_with_attach(self): | def test_incoming_with_attach(self): | ||||
@@ -102,13 +102,13 @@ class TestEmailAccount(unittest.TestCase): | |||||
make(subject = "test-mail-000", content="test mail 000", recipients="test_receiver@example.com", | make(subject = "test-mail-000", content="test mail 000", recipients="test_receiver@example.com", | ||||
send_email=True, sender="test_sender@example.com") | send_email=True, sender="test_sender@example.com") | ||||
mail = email.message_from_string(frappe.get_last_doc("Bulk Email").message) | |||||
mail = email.message_from_string(frappe.get_last_doc("Email Queue").message) | |||||
self.assertTrue("test-mail-000" in mail.get("Subject")) | self.assertTrue("test-mail-000" in mail.get("Subject")) | ||||
def test_sendmail(self): | def test_sendmail(self): | ||||
frappe.flags.sent_mail = None | frappe.flags.sent_mail = None | ||||
frappe.sendmail(sender="test_sender@example.com", recipients="test_recipient@example.com", | frappe.sendmail(sender="test_sender@example.com", recipients="test_recipient@example.com", | ||||
content="test mail 001", subject="test-mail-001") | |||||
content="test mail 001", subject="test-mail-001", delayed=False) | |||||
sent_mail = email.message_from_string(frappe.flags.sent_mail) | sent_mail = email.message_from_string(frappe.flags.sent_mail) | ||||
self.assertTrue("test-mail-001" in sent_mail.get("Subject")) | self.assertTrue("test-mail-001" in sent_mail.get("Subject")) | ||||
@@ -119,7 +119,7 @@ class TestEmailAccount(unittest.TestCase): | |||||
content="test mail 001", subject="test-mail-002", doctype="Email Account", | content="test mail 001", subject="test-mail-002", doctype="Email Account", | ||||
name="_Test Email Account 1", print_format="Standard", send_email=True) | name="_Test Email Account 1", print_format="Standard", send_email=True) | ||||
sent_mail = email.message_from_string(frappe.get_last_doc("Bulk Email").message) | |||||
sent_mail = email.message_from_string(frappe.get_last_doc("Email Queue").message) | |||||
self.assertTrue("test-mail-002" in sent_mail.get("Subject")) | self.assertTrue("test-mail-002" in sent_mail.get("Subject")) | ||||
def test_threading(self): | def test_threading(self): | ||||
@@ -131,7 +131,7 @@ class TestEmailAccount(unittest.TestCase): | |||||
recipients="test_receiver@example.com", sender="test@example.com", | recipients="test_receiver@example.com", sender="test@example.com", | ||||
send_email=True)["name"] | send_email=True)["name"] | ||||
sent_mail = email.message_from_string(frappe.get_last_doc("Bulk Email").message) | |||||
sent_mail = email.message_from_string(frappe.get_last_doc("Email Queue").message) | |||||
with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-1.raw"), "r") as f: | with open(os.path.join(os.path.dirname(__file__), "test_mails", "reply-1.raw"), "r") as f: | ||||
raw = f.read() | raw = f.read() | ||||
@@ -32,7 +32,7 @@ class EmailAlert(Document): | |||||
frappe.throw(_("The Condition '{0}' is invalid").format(self.condition)) | frappe.throw(_("The Condition '{0}' is invalid").format(self.condition)) | ||||
def validate_forbidden_types(self): | def validate_forbidden_types(self): | ||||
forbidden_document_types = ("Bulk Email",) | |||||
forbidden_document_types = ("Email Queue",) | |||||
if (self.document_type in forbidden_document_types | if (self.document_type in forbidden_document_types | ||||
or frappe.get_meta(self.document_type).istable): | or frappe.get_meta(self.document_type).istable): | ||||
# currently email alerts don't work on child tables as events are not fired for each record of child table | # currently email alerts don't work on child tables as events are not fired for each record of child table | ||||
@@ -151,8 +151,7 @@ def evaluate_alert(doc, alert, event): | |||||
subject = frappe.render_template(alert.subject, context) | subject = frappe.render_template(alert.subject, context) | ||||
frappe.sendmail(recipients=recipients, subject=subject, | frappe.sendmail(recipients=recipients, subject=subject, | ||||
message= frappe.render_template(alert.message, context), | |||||
bulk=True, reference_doctype = doc.doctype, reference_name = doc.name, | |||||
message= frappe.render_template(alert.message, context), reference_doctype = doc.doctype, reference_name = doc.name, | |||||
attachments = [frappe.attach_print(doc.doctype, doc.name)] if alert.attach_print else None) | attachments = [frappe.attach_print(doc.doctype, doc.name)] if alert.attach_print else None) | ||||
def get_context(doc): | def get_context(doc): | ||||
@@ -9,7 +9,7 @@ test_records = frappe.get_test_records('Email Alert') | |||||
class TestEmailAlert(unittest.TestCase): | class TestEmailAlert(unittest.TestCase): | ||||
def setUp(self): | def setUp(self): | ||||
frappe.db.sql("""delete from `tabBulk Email`""") | |||||
frappe.db.sql("""delete from `tabEmail Queue`""") | |||||
frappe.set_user("test1@example.com") | frappe.set_user("test1@example.com") | ||||
def tearDown(self): | def tearDown(self): | ||||
@@ -22,14 +22,14 @@ class TestEmailAlert(unittest.TestCase): | |||||
communication.content = "test" | communication.content = "test" | ||||
communication.insert(ignore_permissions=True) | communication.insert(ignore_permissions=True) | ||||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Communication", | |||||
self.assertTrue(frappe.db.get_value("Email Queue", {"reference_doctype": "Communication", | |||||
"reference_name": communication.name, "status":"Not Sent"})) | "reference_name": communication.name, "status":"Not Sent"})) | ||||
frappe.db.sql("""delete from `tabBulk Email`""") | |||||
frappe.db.sql("""delete from `tabEmail Queue`""") | |||||
communication.content = "test 2" | communication.content = "test 2" | ||||
communication.save() | communication.save() | ||||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Communication", | |||||
self.assertTrue(frappe.db.get_value("Email Queue", {"reference_doctype": "Communication", | |||||
"reference_name": communication.name, "status":"Not Sent"})) | "reference_name": communication.name, "status":"Not Sent"})) | ||||
def test_condition(self): | def test_condition(self): | ||||
@@ -39,13 +39,13 @@ class TestEmailAlert(unittest.TestCase): | |||||
event.starts_on = "2014-06-06 12:00:00" | event.starts_on = "2014-06-06 12:00:00" | ||||
event.insert() | event.insert() | ||||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertFalse(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
event.event_type = "Public" | event.event_type = "Public" | ||||
event.save() | event.save() | ||||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertTrue(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
def test_invalid_condition(self): | def test_invalid_condition(self): | ||||
@@ -72,19 +72,19 @@ class TestEmailAlert(unittest.TestCase): | |||||
event.starts_on = "2014-06-06 12:00:00" | event.starts_on = "2014-06-06 12:00:00" | ||||
event.insert() | event.insert() | ||||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertFalse(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
event.subject = "test 1" | event.subject = "test 1" | ||||
event.save() | event.save() | ||||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertFalse(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
event.description = "test" | event.description = "test" | ||||
event.save() | event.save() | ||||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertTrue(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
def test_date_changed(self): | def test_date_changed(self): | ||||
@@ -94,23 +94,23 @@ class TestEmailAlert(unittest.TestCase): | |||||
event.starts_on = "2014-01-01 12:00:00" | event.starts_on = "2014-01-01 12:00:00" | ||||
event.insert() | event.insert() | ||||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertFalse(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | ||||
# not today, so no alert | # not today, so no alert | ||||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertFalse(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
event.starts_on = frappe.utils.add_days(frappe.utils.nowdate(), 2) + " 12:00:00" | event.starts_on = frappe.utils.add_days(frappe.utils.nowdate(), 2) + " 12:00:00" | ||||
event.save() | event.save() | ||||
self.assertFalse(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertFalse(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) | ||||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True) | ||||
# today so show alert | # today so show alert | ||||
self.assertTrue(frappe.db.get_value("Bulk Email", {"reference_doctype": "Event", | |||||
self.assertTrue(frappe.db.get_value("Email Queue", {"reference_doctype": "Event", | |||||
"reference_name": event.name, "status":"Not Sent"})) | "reference_name": event.name, "status":"Not Sent"})) |
@@ -1,4 +1,7 @@ | |||||
frappe.ui.form.on("Bulk Email", { | |||||
// Copyright (c) 2016, Frappe Technologies and contributors | |||||
// For license information, please see license.txt | |||||
frappe.ui.form.on("Email Queue", { | |||||
refresh: function(frm) { | refresh: function(frm) { | ||||
if (frm.doc.status==="Not Sent") { | if (frm.doc.status==="Not Sent") { | ||||
frm.add_custom_button("Send Now", function() { | frm.add_custom_button("Send Now", function() { |
@@ -0,0 +1,308 @@ | |||||
{ | |||||
"allow_copy": 0, | |||||
"allow_import": 0, | |||||
"allow_rename": 0, | |||||
"autoname": "hash", | |||||
"beta": 0, | |||||
"creation": "2012-08-02 15:17:28", | |||||
"custom": 0, | |||||
"description": "Email Queue records.", | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "System", | |||||
"fields": [ | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "sender", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Sender", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Email", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "recipient", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 1, | |||||
"label": "Recipient", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Email", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "message", | |||||
"fieldtype": "Code", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Message", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"default": "Not Sent", | |||||
"fieldname": "status", | |||||
"fieldtype": "Select", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 1, | |||||
"label": "Status", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "\nNot Sent\nSending\nSent\nError\nExpired", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "error", | |||||
"fieldtype": "Code", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Error", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "reference_doctype", | |||||
"fieldtype": "Link", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Reference DocType", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "DocType", | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "reference_name", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Reference DocName", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "communication", | |||||
"fieldtype": "Link", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Communication", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Communication", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 1, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"fieldname": "send_after", | |||||
"fieldtype": "Datetime", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Send After", | |||||
"length": 0, | |||||
"no_copy": 1, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"default": "1", | |||||
"fieldname": "priority", | |||||
"fieldtype": "Int", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_list_view": 0, | |||||
"label": "Priority", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 1, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
} | |||||
], | |||||
"hide_heading": 0, | |||||
"hide_toolbar": 0, | |||||
"icon": "icon-envelope", | |||||
"idx": 1, | |||||
"image_view": 0, | |||||
"in_create": 1, | |||||
"in_dialog": 0, | |||||
"is_submittable": 0, | |||||
"issingle": 0, | |||||
"istable": 0, | |||||
"max_attachments": 0, | |||||
"modified": "2016-06-22 12:23:10.621244", | |||||
"modified_by": "Administrator", | |||||
"module": "Email", | |||||
"name": "Email Queue", | |||||
"owner": "Administrator", | |||||
"permissions": [ | |||||
{ | |||||
"amend": 0, | |||||
"apply_user_permissions": 0, | |||||
"cancel": 0, | |||||
"create": 0, | |||||
"delete": 1, | |||||
"email": 1, | |||||
"export": 0, | |||||
"if_owner": 0, | |||||
"import": 0, | |||||
"permlevel": 0, | |||||
"print": 1, | |||||
"read": 1, | |||||
"report": 1, | |||||
"role": "System Manager", | |||||
"set_user_permissions": 0, | |||||
"share": 0, | |||||
"submit": 0, | |||||
"write": 0 | |||||
} | |||||
], | |||||
"quick_entry": 0, | |||||
"read_only": 0, | |||||
"read_only_onload": 0, | |||||
"sort_order": "DESC", | |||||
"track_seen": 0 | |||||
} |
@@ -1,28 +1,28 @@ | |||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2015, Frappe Technologies and contributors | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe | import frappe | ||||
from frappe.model.document import Document | from frappe.model.document import Document | ||||
from frappe.email.bulk import send_one | |||||
from frappe.utils import now_datetime | |||||
from frappe.email.queue import send_one | |||||
class BulkEmail(Document): | |||||
class EmailQueue(Document): | |||||
pass | pass | ||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def retry_sending(name): | def retry_sending(name): | ||||
doc = frappe.get_doc("Bulk Email", name) | |||||
doc = frappe.get_doc("Email Queue", name) | |||||
if doc and doc.status == "Error": | if doc and doc.status == "Error": | ||||
doc.status = "Not Sent" | doc.status = "Not Sent" | ||||
doc.save(ignore_permissions=True) | doc.save(ignore_permissions=True) | ||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def send_now(name): | def send_now(name): | ||||
doc = frappe.get_doc("Bulk Email", name) | |||||
doc = frappe.get_doc("Email Queue", name) | |||||
send_one(doc, now=True) | send_one(doc, now=True) | ||||
def on_doctype_update(): | def on_doctype_update(): | ||||
"""Add index in `tabCommunication` for `(reference_doctype, reference_name)`""" | """Add index in `tabCommunication` for `(reference_doctype, reference_name)`""" | ||||
frappe.db.add_index('Bulk Email', ('status', 'send_after', 'priority', 'creation'), 'index_bulk_flush') | |||||
frappe.db.add_index('Email Queue', ('status', 'send_after', 'priority', 'creation'), 'index_bulk_flush') |
@@ -1,4 +1,4 @@ | |||||
frappe.listview_settings['Bulk Email'] = { | |||||
frappe.listview_settings['Email Queue'] = { | |||||
get_indicator: function(doc) { | get_indicator: function(doc) { | ||||
colour = {'Sent': 'green', 'Sending': 'blue', 'Not Sent': 'grey', 'Error': 'red', 'Expired': 'orange'}; | colour = {'Sent': 'green', 'Sending': 'blue', 'Not Sent': 'grey', 'Error': 'red', 'Expired': 'orange'}; | ||||
return [__(doc.status), colour[doc.status], "status,=," + doc.status]; | return [__(doc.status), colour[doc.status], "status,=," + doc.status]; |
@@ -0,0 +1,12 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2015, Frappe Technologies and Contributors | |||||
# See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
import unittest | |||||
# test_records = frappe.get_test_records('Email Queue') | |||||
class TestEmailQueue(unittest.TestCase): | |||||
pass |
@@ -14,13 +14,13 @@ from frappe.utils import get_url, nowdate, encode, now_datetime, add_days, split | |||||
from rq.timeouts import JobTimeoutException | from rq.timeouts import JobTimeoutException | ||||
from frappe.utils.scheduler import log | from frappe.utils.scheduler import log | ||||
class BulkLimitCrossedError(frappe.ValidationError): pass | |||||
class EmailLimitCrossedError(frappe.ValidationError): pass | |||||
def send(recipients=None, sender=None, subject=None, message=None, reference_doctype=None, | def send(recipients=None, sender=None, subject=None, message=None, reference_doctype=None, | ||||
reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, | reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None, | ||||
attachments=None, reply_to=None, cc=(), show_as_cc=(), message_id=None, in_reply_to=None, send_after=None, | attachments=None, reply_to=None, cc=(), show_as_cc=(), message_id=None, in_reply_to=None, send_after=None, | ||||
expose_recipients=False, bulk_priority=1, communication=None): | |||||
"""Add email to sending queue (Bulk Email) | |||||
expose_recipients=False, send_priority=1, communication=None): | |||||
"""Add email to sending queue (Email Queue) | |||||
:param recipients: List of recipients. | :param recipients: List of recipients. | ||||
:param sender: Email sender. | :param sender: Email sender. | ||||
@@ -28,18 +28,18 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc | |||||
:param message: Email message. | :param message: Email message. | ||||
:param reference_doctype: Reference DocType of caller document. | :param reference_doctype: Reference DocType of caller document. | ||||
:param reference_name: Reference name of caller document. | :param reference_name: Reference name of caller document. | ||||
:param bulk_priority: Priority for bulk email, default 1. | |||||
:param unsubscribe_method: URL method for unsubscribe. Default is `/api/method/frappe.email.bulk.unsubscribe`. | |||||
:param send_priority: Priority for Email Queue, default 1. | |||||
:param unsubscribe_method: URL method for unsubscribe. Default is `/api/method/frappe.email.queue.unsubscribe`. | |||||
:param unsubscribe_params: additional params for unsubscribed links. default are name, doctype, email | :param unsubscribe_params: additional params for unsubscribed links. default are name, doctype, email | ||||
:param attachments: Attachments to be sent. | :param attachments: Attachments to be sent. | ||||
:param reply_to: Reply to be captured here (default inbox) | :param reply_to: Reply to be captured here (default inbox) | ||||
:param message_id: Used for threading. If a reply is received to this email, Message-Id is sent back as In-Reply-To in received email. | :param message_id: Used for threading. If a reply is received to this email, Message-Id is sent back as In-Reply-To in received email. | ||||
:param in_reply_to: Used to send the Message-Id of a received email back as In-Reply-To. | :param in_reply_to: Used to send the Message-Id of a received email back as In-Reply-To. | ||||
:param send_after: Send this email after the given datetime. If value is in integer, then `send_after` will be the automatically set to no of days from current date. | :param send_after: Send this email after the given datetime. If value is in integer, then `send_after` will be the automatically set to no of days from current date. | ||||
:param communication: Communication link to be set in Bulk Email record | |||||
:param communication: Communication link to be set in Email Queue record | |||||
""" | """ | ||||
if not unsubscribe_method: | if not unsubscribe_method: | ||||
unsubscribe_method = "/api/method/frappe.email.bulk.unsubscribe" | |||||
unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe" | |||||
if not recipients: | if not recipients: | ||||
return | return | ||||
@@ -54,7 +54,7 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc | |||||
if not sender or sender == "Administrator": | if not sender or sender == "Administrator": | ||||
sender = email_account.default_sender | sender = email_account.default_sender | ||||
check_bulk_limit(recipients) | |||||
check_email_limit(recipients) | |||||
formatted = get_formatted_html(subject, message, email_account=email_account) | formatted = get_formatted_html(subject, message, email_account=email_account) | ||||
@@ -104,15 +104,15 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc | |||||
# add to queue | # add to queue | ||||
add(email, sender, subject, email_content, email_text_context, reference_doctype, | add(email, sender, subject, email_content, email_text_context, reference_doctype, | ||||
reference_name, attachments, reply_to, cc, message_id, in_reply_to, send_after, bulk_priority, email_account=email_account, communication=communication) | |||||
reference_name, attachments, reply_to, cc, message_id, in_reply_to, send_after, send_priority, email_account=email_account, communication=communication) | |||||
def add(email, sender, subject, formatted, text_content=None, | def add(email, sender, subject, formatted, text_content=None, | ||||
reference_doctype=None, reference_name=None, attachments=None, reply_to=None, | reference_doctype=None, reference_name=None, attachments=None, reply_to=None, | ||||
cc=(), message_id=None, in_reply_to=None, send_after=None, bulk_priority=1, email_account=None, communication=None): | |||||
"""add to bulk mail queue""" | |||||
e = frappe.new_doc('Bulk Email') | |||||
cc=(), message_id=None, in_reply_to=None, send_after=None, send_priority=1, email_account=None, communication=None): | |||||
"""Add to Email Queue""" | |||||
e = frappe.new_doc('Email Queue') | |||||
e.recipient = email | e.recipient = email | ||||
e.priority = bulk_priority | |||||
e.priority = send_priority | |||||
try: | try: | ||||
mail = get_email(email, sender=sender, formatted=formatted, subject=subject, | mail = get_email(email, sender=sender, formatted=formatted, subject=subject, | ||||
@@ -137,8 +137,8 @@ def add(email, sender, subject, formatted, text_content=None, | |||||
e.send_after = send_after | e.send_after = send_after | ||||
e.insert(ignore_permissions=True) | e.insert(ignore_permissions=True) | ||||
def check_bulk_limit(recipients): | |||||
# if using settings from site_config.json, check bulk limit | |||||
def check_email_limit(recipients): | |||||
# if using settings from site_config.json, check email limit | |||||
# No limit for own email settings | # No limit for own email settings | ||||
smtp_server = SMTPServer() | smtp_server = SMTPServer() | ||||
@@ -147,14 +147,14 @@ def check_bulk_limit(recipients): | |||||
or frappe.flags.in_test): | or frappe.flags.in_test): | ||||
# get count of mails sent this month | # get count of mails sent this month | ||||
this_month = frappe.db.sql("""select count(name) from `tabBulk Email` where | |||||
this_month = frappe.db.sql("""select count(name) from `tabEmail Queue` where | |||||
status='Sent' and MONTH(creation)=MONTH(CURDATE())""")[0][0] | status='Sent' and MONTH(creation)=MONTH(CURDATE())""")[0][0] | ||||
monthly_bulk_mail_limit = frappe.conf.get('monthly_bulk_mail_limit') or 500 | |||||
monthly_email_limit = frappe.conf.get('monthly_email_limit') or 500 | |||||
if (this_month + len(recipients)) > monthly_bulk_mail_limit: | |||||
throw(_("Cannot send this email. You have crossed the sending limit of {0} emails for this month.").format(monthly_bulk_mail_limit), | |||||
BulkLimitCrossedError) | |||||
if (this_month + len(recipients)) > monthly_email_limit: | |||||
throw(_("Cannot send this email. You have crossed the sending limit of {0} emails for this month.").format(monthly_email_limit), | |||||
EmailLimitCrossedError) | |||||
def get_unsubscribe_link(reference_doctype, reference_name, | def get_unsubscribe_link(reference_doctype, reference_name, | ||||
email, recipients, expose_recipients, show_as_cc, | email, recipients, expose_recipients, show_as_cc, | ||||
@@ -241,21 +241,21 @@ def return_unsubscribed_page(email, doctype, name): | |||||
def flush(from_test=False): | def flush(from_test=False): | ||||
"""flush email queue, every time: called from scheduler""" | """flush email queue, every time: called from scheduler""" | ||||
# additional check | # additional check | ||||
check_bulk_limit([]) | |||||
check_email_limit([]) | |||||
auto_commit = not from_test | auto_commit = not from_test | ||||
if frappe.are_emails_muted(): | if frappe.are_emails_muted(): | ||||
msgprint(_("Emails are muted")) | msgprint(_("Emails are muted")) | ||||
from_test = True | from_test = True | ||||
frappe.db.sql("""update `tabBulk Email` set status='Expired' | |||||
frappe.db.sql("""update `tabEmail Queue` set status='Expired' | |||||
where datediff(curdate(), creation) > 7 and status='Not Sent'""", auto_commit=auto_commit) | where datediff(curdate(), creation) > 7 and status='Not Sent'""", auto_commit=auto_commit) | ||||
smtpserver = SMTPServer() | smtpserver = SMTPServer() | ||||
for i in xrange(500): | for i in xrange(500): | ||||
# don't use for update here, as it leads deadlocks | # don't use for update here, as it leads deadlocks | ||||
email = frappe.db.sql('''select * from `tabBulk Email` | |||||
email = frappe.db.sql('''select * from `tabEmail Queue` | |||||
where status='Not Sent' and (send_after is null or send_after < %(now)s) | where status='Not Sent' and (send_after is null or send_after < %(now)s) | ||||
order by priority desc, creation asc | order by priority desc, creation asc | ||||
limit 1''', { 'now': now_datetime() }, as_dict=True) | limit 1''', { 'now': now_datetime() }, as_dict=True) | ||||
@@ -272,15 +272,15 @@ def flush(from_test=False): | |||||
# frappe.db.commit() | # frappe.db.commit() | ||||
def send_one(email, smtpserver=None, auto_commit=True, now=False): | def send_one(email, smtpserver=None, auto_commit=True, now=False): | ||||
'''Send bulk email with given smtpserver''' | |||||
'''Send Email Queue with given smtpserver''' | |||||
status = frappe.db.sql('''select status from `tabBulk Email` where name=%s for update''', email.name)[0][0] | |||||
status = frappe.db.sql('''select status from `tabEmail Queue` where name=%s for update''', email.name)[0][0] | |||||
if status != 'Not Sent': | if status != 'Not Sent': | ||||
# rollback to release lock and return | # rollback to release lock and return | ||||
frappe.db.rollback() | frappe.db.rollback() | ||||
return | return | ||||
frappe.db.sql("""update `tabBulk Email` set status='Sending', modified=%s where name=%s""", | |||||
frappe.db.sql("""update `tabEmail Queue` set status='Sending', modified=%s where name=%s""", | |||||
(now_datetime(), email.name), auto_commit=auto_commit) | (now_datetime(), email.name), auto_commit=auto_commit) | ||||
if email.communication: | if email.communication: | ||||
@@ -292,7 +292,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False): | |||||
smtpserver.setup_email_account(email.reference_doctype) | smtpserver.setup_email_account(email.reference_doctype) | ||||
smtpserver.sess.sendmail(email.sender, email.recipient, encode(email.message)) | smtpserver.sess.sendmail(email.sender, email.recipient, encode(email.message)) | ||||
frappe.db.sql("""update `tabBulk Email` set status='Sent', modified=%s where name=%s""", | |||||
frappe.db.sql("""update `tabEmail Queue` set status='Sent', modified=%s where name=%s""", | |||||
(now_datetime(), email.name), auto_commit=auto_commit) | (now_datetime(), email.name), auto_commit=auto_commit) | ||||
if email.communication: | if email.communication: | ||||
@@ -305,7 +305,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False): | |||||
JobTimeoutException): | JobTimeoutException): | ||||
# bad connection/timeout, retry later | # bad connection/timeout, retry later | ||||
frappe.db.sql("""update `tabBulk Email` set status='Not Sent', modified=%s where name=%s""", | |||||
frappe.db.sql("""update `tabEmail Queue` set status='Not Sent', modified=%s where name=%s""", | |||||
(now_datetime(), email.name), auto_commit=auto_commit) | (now_datetime(), email.name), auto_commit=auto_commit) | ||||
if email.communication: | if email.communication: | ||||
@@ -317,7 +317,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False): | |||||
except Exception, e: | except Exception, e: | ||||
frappe.db.rollback() | frappe.db.rollback() | ||||
frappe.db.sql("""update `tabBulk Email` set status='Error', error=%s | |||||
frappe.db.sql("""update `tabEmail Queue` set status='Error', error=%s | |||||
where name=%s""", (unicode(e), email.name), auto_commit=auto_commit) | where name=%s""", (unicode(e), email.name), auto_commit=auto_commit) | ||||
if email.communication: | if email.communication: | ||||
@@ -328,14 +328,14 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False): | |||||
else: | else: | ||||
# log to scheduler log | # log to scheduler log | ||||
log('frappe.email.bulk.flush', unicode(e)) | |||||
log('frappe.email.queue.flush', unicode(e)) | |||||
def clear_outbox(): | def clear_outbox(): | ||||
"""Remove mails older than 31 days in Outbox. Called daily via scheduler.""" | """Remove mails older than 31 days in Outbox. Called daily via scheduler.""" | ||||
frappe.db.sql("""delete from `tabBulk Email` where | |||||
frappe.db.sql("""delete from `tabEmail Queue` where | |||||
datediff(now(), creation) > 31""") | datediff(now(), creation) > 31""") | ||||
def prevent_bulk_email_delete(doc, method): | |||||
def prevent_email_queue_delete(doc, method): | |||||
from frappe.limits import get_limits | from frappe.limits import get_limits | ||||
if frappe.session.user != 'Administrator' and get_limits().get('block_bulk_email_delete'): | if frappe.session.user != 'Administrator' and get_limits().get('block_bulk_email_delete'): | ||||
frappe.throw(_('Only Administrator can delete Bulk Email')) | |||||
frappe.throw(_('Only Administrator can delete Email Queue')) |
@@ -99,8 +99,8 @@ doc_events = { | |||||
"User": { | "User": { | ||||
"validate": "frappe.utils.user.validate_user_limit" | "validate": "frappe.utils.user.validate_user_limit" | ||||
}, | }, | ||||
"Bulk Email": { | |||||
"on_trash": "frappe.email.bulk.prevent_bulk_email_delete" | |||||
"Email Queue": { | |||||
"on_trash": "frappe.email.queue.prevent_email_queue_delete" | |||||
}, | }, | ||||
"*": { | "*": { | ||||
"after_insert": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | "after_insert": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | ||||
@@ -124,7 +124,7 @@ doc_events = { | |||||
scheduler_events = { | scheduler_events = { | ||||
"all": [ | "all": [ | ||||
"frappe.email.bulk.flush", | |||||
"frappe.email.queue.flush", | |||||
"frappe.email.doctype.email_account.email_account.pull", | "frappe.email.doctype.email_account.email_account.pull", | ||||
"frappe.email.doctype.email_account.email_account.notify_unreplied", | "frappe.email.doctype.email_account.email_account.notify_unreplied", | ||||
"frappe.utils.error.collect_error_snapshots", | "frappe.utils.error.collect_error_snapshots", | ||||
@@ -132,7 +132,7 @@ scheduler_events = { | |||||
'frappe.model.utils.list_settings.sync_list_settings' | 'frappe.model.utils.list_settings.sync_list_settings' | ||||
], | ], | ||||
"daily": [ | "daily": [ | ||||
"frappe.email.bulk.clear_outbox", | |||||
"frappe.email.queue.clear_outbox", | |||||
"frappe.desk.notifications.clear_notifications", | "frappe.desk.notifications.clear_notifications", | ||||
"frappe.core.doctype.scheduler_log.scheduler_log.set_old_logs_as_seen", | "frappe.core.doctype.scheduler_log.scheduler_log.set_old_logs_as_seen", | ||||
"frappe.desk.doctype.event.event.send_event_digest", | "frappe.desk.doctype.event.event.send_event_digest", | ||||
@@ -35,7 +35,7 @@ def check_if_expired(): | |||||
# if expired, stop user from logging in | # if expired, stop user from logging in | ||||
expires_on = formatdate(get_limits().get("expiry")) | expires_on = formatdate(get_limits().get("expiry")) | ||||
support_email = get_limits().get("support_email") or _("your provider") | support_email = get_limits().get("support_email") or _("your provider") | ||||
frappe.throw(_("""Your subscription expired on {0}. | frappe.throw(_("""Your subscription expired on {0}. | ||||
To extend please send an email to {1}""").format(expires_on, support_email), | To extend please send an email to {1}""").format(expires_on, support_email), | ||||
SiteExpiredError) | SiteExpiredError) | ||||
@@ -72,7 +72,7 @@ def get_expiry_message(): | |||||
def get_limits(): | def get_limits(): | ||||
limits = frappe.get_conf().get("limits") or {} | limits = frappe.get_conf().get("limits") or {} | ||||
day = frappe.utils.add_months(frappe.utils.today(), -1) | day = frappe.utils.add_months(frappe.utils.today(), -1) | ||||
limits["bulk_count"] = frappe.db.count("Bulk Email", filters={'creation': ['>', day]}) | |||||
limits["emails_sent"] = frappe.db.count("Email Queue", filters={'creation': ['>', day]}) | |||||
return limits | return limits | ||||
@@ -15,6 +15,7 @@ execute:frappe.reload_doc('custom', 'doctype', 'property_setter') #2014-12-31-1 | |||||
execute:frappe.reload_doc('core', 'doctype', 'patch_log') #2016-10-31 | execute:frappe.reload_doc('core', 'doctype', 'patch_log') #2016-10-31 | ||||
execute:frappe.reload_doctype("File") # 2015-10-19 | execute:frappe.reload_doctype("File") # 2015-10-19 | ||||
execute:frappe.reload_doc('core', 'doctype', 'error_snapshot') | execute:frappe.reload_doc('core', 'doctype', 'error_snapshot') | ||||
frappe.patches.v7_0.rename_bulk_email_to_email_queue | |||||
execute:frappe.db.sql("alter table `tabSessions` modify `user` varchar(255), engine=InnoDB") | execute:frappe.db.sql("alter table `tabSessions` modify `user` varchar(255), engine=InnoDB") | ||||
execute:frappe.db.sql("delete from `tabDocField` where parent='0'") | execute:frappe.db.sql("delete from `tabDocField` where parent='0'") | ||||
@@ -6,14 +6,14 @@ import frappe | |||||
def execute(): | def execute(): | ||||
try: | try: | ||||
frappe.db.sql("alter table `tabBulk Email` change `ref_docname` `reference_name` varchar(255)") | |||||
frappe.db.sql("alter table `tabEmail Queue` change `ref_docname` `reference_name` varchar(255)") | |||||
except Exception, e: | except Exception, e: | ||||
if e.args[0] not in (1054, 1060): | if e.args[0] not in (1054, 1060): | ||||
raise | raise | ||||
try: | try: | ||||
frappe.db.sql("alter table `tabBulk Email` change `ref_doctype` `reference_doctype` varchar(255)") | |||||
frappe.db.sql("alter table `tabEmail Queue` change `ref_doctype` `reference_doctype` varchar(255)") | |||||
except Exception, e: | except Exception, e: | ||||
if e.args[0] not in (1054, 1060): | if e.args[0] not in (1054, 1060): | ||||
raise | raise | ||||
frappe.reload_doctype("Bulk Email") | |||||
frappe.reload_doctype("Email Queue") |
@@ -9,7 +9,7 @@ def execute(): | |||||
("desk", ("feed", "event", "event_role", "todo", "note")), | ("desk", ("feed", "event", "event_role", "todo", "note")), | ||||
("custom", ("custom_field", "custom_script", "customize_form", | ("custom", ("custom_field", "custom_script", "customize_form", | ||||
"customize_form_field", "property_setter")), | "customize_form_field", "property_setter")), | ||||
("email", ("bulk_email", "email_alert", "email_alert_recipient", "standard_reply")), | |||||
("email", ("email_queue", "email_alert", "email_alert_recipient", "standard_reply")), | |||||
("geo", ("country", "currency")), | ("geo", ("country", "currency")), | ||||
("print", ("letter_head", "print_format", "print_settings")) | ("print", ("letter_head", "print_format", "print_settings")) | ||||
) | ) | ||||
@@ -0,0 +1,4 @@ | |||||
import frappe | |||||
def execute(): | |||||
frappe.rename_doc('DocType', 'Bulk Email', 'Email Queue') |
@@ -2,4 +2,4 @@ import frappe | |||||
from frappe.utils import now_datetime | from frappe.utils import now_datetime | ||||
def execute(): | def execute(): | ||||
frappe.db.sql('update `tabBulk Email` set send_after=%s where send_after is null', now_datetime()) | |||||
frappe.db.sql('update `tabEmail Queue` set send_after=%s where send_after is null', now_datetime()) |
@@ -49,7 +49,7 @@ def add_comment(args=None): | |||||
message += "<p><a href='{0}/{1}' style='font-size: 80%'>{2}</a></p>".format(frappe.utils.get_request_site_address(), | message += "<p><a href='{0}/{1}' style='font-size: 80%'>{2}</a></p>".format(frappe.utils.get_request_site_address(), | ||||
page_name, _("View it in your browser")) | page_name, _("View it in your browser")) | ||||
from frappe.email.bulk import send | |||||
from frappe.email.queue import send | |||||
send(recipients=recipients, | send(recipients=recipients, | ||||
subject = _("New comment on {0} {1}").format(doc.doctype, doc.name), | subject = _("New comment on {0} {1}").format(doc.doctype, doc.name), | ||||
@@ -26,4 +26,4 @@ class TestDB(unittest.TestCase): | |||||
def test_multiple_queries(self): | def test_multiple_queries(self): | ||||
# implicit commit | # implicit commit | ||||
self.assertRaises(frappe.SQLError, frappe.db.sql, """select name from `tabUser`; truncate `tabBulk Email`""") | |||||
self.assertRaises(frappe.SQLError, frappe.db.sql, """select name from `tabUser`; truncate `tabEmail Queue`""") |
@@ -12,81 +12,81 @@ make_test_records("Email Account") | |||||
class TestEmail(unittest.TestCase): | class TestEmail(unittest.TestCase): | ||||
def setUp(self): | def setUp(self): | ||||
frappe.db.sql("""delete from `tabEmail Unsubscribe`""") | frappe.db.sql("""delete from `tabEmail Unsubscribe`""") | ||||
frappe.db.sql("""delete from `tabBulk Email`""") | |||||
frappe.db.sql("""delete from `tabEmail Queue`""") | |||||
def test_send(self): | def test_send(self): | ||||
from frappe.email import sendmail | from frappe.email import sendmail | ||||
sendmail('test@example.com', subject='Test Mail', msg="Test Content") | sendmail('test@example.com', subject='Test Mail', msg="Test Content") | ||||
def test_bulk(self, send_after=None): | |||||
from frappe.email.bulk import send | |||||
def test_email_queue(self, send_after=None): | |||||
from frappe.email.queue import send | |||||
send(recipients = ['test@example.com', 'test1@example.com'], | send(recipients = ['test@example.com', 'test1@example.com'], | ||||
sender="admin@example.com", | sender="admin@example.com", | ||||
reference_doctype='User', reference_name='Administrator', | reference_doctype='User', reference_name='Administrator', | ||||
subject='Testing Bulk', message='This is a bulk mail!', send_after=send_after) | |||||
subject='Testing Queue', message='This mail is queued!', send_after=send_after) | |||||
bulk = frappe.db.sql("""select * from `tabBulk Email` where status='Not Sent'""", as_dict=1) | |||||
self.assertEquals(len(bulk), 2) | |||||
self.assertTrue('test@example.com' in [d['recipient'] for d in bulk]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in bulk]) | |||||
self.assertTrue('Unsubscribe' in bulk[0]['message']) | |||||
email_queue = frappe.db.sql("""select * from `tabEmail Queue` where status='Not Sent'""", as_dict=1) | |||||
self.assertEquals(len(email_queue), 2) | |||||
self.assertTrue('test@example.com' in [d['recipient'] for d in email_queue]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in email_queue]) | |||||
self.assertTrue('Unsubscribe' in email_queue[0]['message']) | |||||
def test_flush(self): | def test_flush(self): | ||||
self.test_bulk(send_after = 1) | |||||
from frappe.email.bulk import flush | |||||
self.test_email_queue(send_after = 1) | |||||
from frappe.email.queue import flush | |||||
flush(from_test=True) | flush(from_test=True) | ||||
bulk = frappe.db.sql("""select * from `tabBulk Email` where status='Sent'""", as_dict=1) | |||||
self.assertEquals(len(bulk), 0) | |||||
email_queue = frappe.db.sql("""select * from `tabEmail Queue` where status='Sent'""", as_dict=1) | |||||
self.assertEquals(len(email_queue), 0) | |||||
def test_send_after(self): | def test_send_after(self): | ||||
self.test_bulk() | |||||
from frappe.email.bulk import flush | |||||
self.test_email_queue() | |||||
from frappe.email.queue import flush | |||||
flush(from_test=True) | flush(from_test=True) | ||||
bulk = frappe.db.sql("""select * from `tabBulk Email` where status='Sent'""", as_dict=1) | |||||
self.assertEquals(len(bulk), 2) | |||||
self.assertTrue('test@example.com' in [d['recipient'] for d in bulk]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in bulk]) | |||||
email_queue = frappe.db.sql("""select * from `tabEmail Queue` where status='Sent'""", as_dict=1) | |||||
self.assertEquals(len(email_queue), 2) | |||||
self.assertTrue('test@example.com' in [d['recipient'] for d in email_queue]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in email_queue]) | |||||
def test_expired(self): | def test_expired(self): | ||||
self.test_bulk() | |||||
frappe.db.sql("update `tabBulk Email` set creation='2010-01-01 12:00:00'") | |||||
from frappe.email.bulk import flush | |||||
self.test_email_queue() | |||||
frappe.db.sql("update `tabEmail Queue` set creation='2010-01-01 12:00:00'") | |||||
from frappe.email.queue import flush | |||||
flush(from_test=True) | flush(from_test=True) | ||||
bulk = frappe.db.sql("""select * from `tabBulk Email` where status='Expired'""", as_dict=1) | |||||
self.assertEquals(len(bulk), 2) | |||||
self.assertTrue('test@example.com' in [d['recipient'] for d in bulk]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in bulk]) | |||||
email_queue = frappe.db.sql("""select * from `tabEmail Queue` where status='Expired'""", as_dict=1) | |||||
self.assertEquals(len(email_queue), 2) | |||||
self.assertTrue('test@example.com' in [d['recipient'] for d in email_queue]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in email_queue]) | |||||
def test_unsubscribe(self): | def test_unsubscribe(self): | ||||
from frappe.email.bulk import unsubscribe, send | |||||
from frappe.email.queue import unsubscribe, send | |||||
unsubscribe(doctype="User", name="Administrator", email="test@example.com") | unsubscribe(doctype="User", name="Administrator", email="test@example.com") | ||||
self.assertTrue(frappe.db.get_value("Email Unsubscribe", | self.assertTrue(frappe.db.get_value("Email Unsubscribe", | ||||
{"reference_doctype": "User", "reference_name": "Administrator", "email": "test@example.com"})) | {"reference_doctype": "User", "reference_name": "Administrator", "email": "test@example.com"})) | ||||
before = frappe.db.sql("""select count(name) from `tabBulk Email` where status='Not Sent'""")[0][0] | |||||
before = frappe.db.sql("""select count(name) from `tabEmail Queue` where status='Not Sent'""")[0][0] | |||||
send(recipients = ['test@example.com', 'test1@example.com'], | send(recipients = ['test@example.com', 'test1@example.com'], | ||||
sender="admin@example.com", | sender="admin@example.com", | ||||
reference_doctype='User', reference_name= "Administrator", | reference_doctype='User', reference_name= "Administrator", | ||||
subject='Testing Bulk', message='This is a bulk mail!') | |||||
subject='Testing Email Queue', message='This is mail is queued!') | |||||
# this is sent async (?) | # this is sent async (?) | ||||
bulk = frappe.db.sql("""select * from `tabBulk Email` where status='Not Sent'""", | |||||
email_queue = frappe.db.sql("""select * from `tabEmail Queue` where status='Not Sent'""", | |||||
as_dict=1) | as_dict=1) | ||||
self.assertEquals(len(bulk), before + 1) | |||||
self.assertFalse('test@example.com' in [d['recipient'] for d in bulk]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in bulk]) | |||||
self.assertTrue('Unsubscribe' in bulk[0]['message']) | |||||
def test_bulk_limit(self): | |||||
from frappe.email.bulk import send, BulkLimitCrossedError | |||||
self.assertRaises(BulkLimitCrossedError, send, | |||||
self.assertEquals(len(email_queue), before + 1) | |||||
self.assertFalse('test@example.com' in [d['recipient'] for d in email_queue]) | |||||
self.assertTrue('test1@example.com' in [d['recipient'] for d in email_queue]) | |||||
self.assertTrue('Unsubscribe' in email_queue[0]['message']) | |||||
def test_email_queue_limit(self): | |||||
from frappe.email.queue import send, EmailLimitCrossedError | |||||
self.assertRaises(EmailLimitCrossedError, send, | |||||
recipients=['test@example.com']*1000, | recipients=['test@example.com']*1000, | ||||
sender="admin@example.com", | sender="admin@example.com", | ||||
reference_doctype = "User", reference_name="Administrator", | reference_doctype = "User", reference_name="Administrator", | ||||
subject='Testing Bulk', message='This is a bulk mail!') | |||||
subject='Testing Email Queue', message='This email is queued!') | |||||
def test_image_parsing(self): | def test_image_parsing(self): | ||||
import re | import re | ||||