[rename] Bulk Email to Email Queue
This commit is contained in:
parent
acc4595fc7
commit
8a91f1a790
33 changed files with 475 additions and 474 deletions
|
|
@ -7,7 +7,6 @@ globals attached to frappe module
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from werkzeug.local import Local, release_local
|
||||
from functools import wraps
|
||||
import os, importlib, inspect, json
|
||||
|
||||
# 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 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)
|
||||
|
||||
|
|
@ -355,11 +354,11 @@ def get_request_header(key, default=None):
|
|||
return request.headers.get(key, default)
|
||||
|
||||
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,
|
||||
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**.
|
||||
|
||||
|
||||
|
|
@ -368,8 +367,8 @@ def sendmail(recipients=(), sender="", subject="No Subject", message="No Message
|
|||
:param subject: Email Subject.
|
||||
:param message: (or `content`) Email Content.
|
||||
: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.
|
||||
:param send_priority: Priority for Email Queue, default 1.
|
||||
:param reference_doctype: (or `doctype`) Append as communication to this DocType.
|
||||
: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`
|
||||
|
|
@ -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 send_after: Send after the given datetime.
|
||||
: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,
|
||||
reference_doctype = doctype or reference_doctype, reference_name = name or reference_name,
|
||||
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,
|
||||
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:
|
||||
import frappe.email
|
||||
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):
|
||||
""" No_copy fields also get copied."""
|
||||
import copy
|
||||
from frappe.model import optional_fields, default_fields
|
||||
|
||||
def remove_no_copy_fields(d):
|
||||
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)
|
||||
|
||||
|
||||
@click.command('add-bulk-email')
|
||||
@click.command('add-to-email-queue')
|
||||
@click.argument('email')
|
||||
@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)
|
||||
with frappe.init_site(site):
|
||||
frappe.connect()
|
||||
kwargs = json.loads(email)
|
||||
kwargs['as_bulk'] = True
|
||||
kwargs['delayed'] = True
|
||||
frappe.sendmail(**kwargs)
|
||||
frappe.db.commit()
|
||||
|
||||
|
|
@ -408,7 +408,6 @@ def get_version():
|
|||
print "{0} {1}".format(m, module.__version__)
|
||||
|
||||
commands = [
|
||||
add_bulk_email,
|
||||
build,
|
||||
build_website,
|
||||
clear_cache,
|
||||
|
|
@ -433,4 +432,5 @@ commands = [
|
|||
sync_www,
|
||||
watch,
|
||||
_bulk_rename,
|
||||
add_to_email_queue,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ def get_data():
|
|||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Bulk Email",
|
||||
"name": "Email Queue",
|
||||
"description": _("Background Email Queue"),
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -104,8 +104,7 @@ def notify_mentions(doc):
|
|||
recipients=recipients,
|
||||
sender=frappe.session.user,
|
||||
subject=subject,
|
||||
message=message,
|
||||
bulk=True
|
||||
message=message
|
||||
)
|
||||
|
||||
def get_comments_from_parent(doc):
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ class Communication(Document):
|
|||
|
||||
def notify(self, print_html=None, print_format=None, attachments=None,
|
||||
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_format: Attach print format of parent document
|
||||
|
|
@ -193,9 +193,9 @@ class Communication(Document):
|
|||
frappe.local.flags.commit = True
|
||||
|
||||
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
|
||||
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'):
|
||||
delivery_status = 'Sending'
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from email.utils import formataddr, parseaddr
|
|||
from frappe.utils import (get_url, get_formatted_email, cint,
|
||||
validate_email_add, split_emails, time_diff_in_seconds)
|
||||
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
|
||||
import frappe.email.smtp
|
||||
import MySQLdb
|
||||
|
|
@ -89,7 +89,7 @@ def validate_email(doc):
|
|||
|
||||
def notify(doc, print_html=None, print_format=None, attachments=None,
|
||||
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_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,
|
||||
recipients=recipients, cc=cc)
|
||||
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",
|
||||
communication_name=doc.name,
|
||||
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,
|
||||
message_id=doc.name,
|
||||
unsubscribe_message=_("Leave this conversation"),
|
||||
bulk=True,
|
||||
delayed=True,
|
||||
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_format: Attach print format of parent document."""
|
||||
|
||||
|
||||
view_link = frappe.utils.cint(frappe.db.get_value("Print Settings", "Print Settings", "attach_view_link"))
|
||||
|
||||
if print_format and view_link:
|
||||
|
|
|
|||
|
|
@ -189,19 +189,21 @@ class User(Document):
|
|||
(self.first_name and " " or '') + (self.last_name or '')
|
||||
|
||||
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):
|
||||
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):
|
||||
from frappe.utils import random_string, get_url
|
||||
from frappe.utils import get_url
|
||||
|
||||
link = self.reset_password()
|
||||
self.send_login_mail(_("Verify Your Account"), "templates/emails/new_user.html",
|
||||
{"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"""
|
||||
from frappe.utils.user import get_user_fullname
|
||||
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
|
||||
|
||||
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):
|
||||
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"),
|
||||
message=message, bulk=True)
|
||||
message=message)
|
||||
|
||||
def extract_mentions(txt):
|
||||
"""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.sendmail(recipients=user.email, subject=frappe._("Upcoming Events for Today"),
|
||||
content = text, bulk=True)
|
||||
content = text)
|
||||
|
||||
@frappe.whitelist()
|
||||
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),
|
||||
"message": txt,
|
||||
"link": get_url()
|
||||
}),
|
||||
bulk=True)
|
||||
}))
|
||||
except frappe.OutgoingEmailError:
|
||||
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,
|
||||
message_id = communication.name,
|
||||
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):
|
||||
"""Return list of emails listed"""
|
||||
|
|
@ -398,7 +397,7 @@ def notify_unreplied():
|
|||
# if status is still open
|
||||
frappe.sendmail(recipients=email_account.get_unreplied_notification_emails(),
|
||||
content=comm.content, subject=comm.subject, doctype= comm.reference_doctype,
|
||||
name=comm.reference_name, bulk=True)
|
||||
name=comm.reference_name)
|
||||
|
||||
# update flag
|
||||
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.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()
|
||||
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"}))
|
||||
|
||||
def test_incoming_with_attach(self):
|
||||
|
|
@ -102,7 +102,7 @@ class TestEmailAccount(unittest.TestCase):
|
|||
make(subject = "test-mail-000", content="test mail 000", recipients="test_receiver@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"))
|
||||
|
||||
def test_sendmail(self):
|
||||
|
|
@ -119,7 +119,7 @@ class TestEmailAccount(unittest.TestCase):
|
|||
content="test mail 001", subject="test-mail-002", doctype="Email Account",
|
||||
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"))
|
||||
|
||||
def test_threading(self):
|
||||
|
|
@ -131,7 +131,7 @@ class TestEmailAccount(unittest.TestCase):
|
|||
recipients="test_receiver@example.com", sender="test@example.com",
|
||||
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:
|
||||
raw = f.read()
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class EmailAlert(Document):
|
|||
frappe.throw(_("The Condition '{0}' is invalid").format(self.condition))
|
||||
|
||||
def validate_forbidden_types(self):
|
||||
forbidden_document_types = ("Bulk Email",)
|
||||
forbidden_document_types = ("Email Queue",)
|
||||
if (self.document_type in forbidden_document_types
|
||||
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
|
||||
|
|
@ -151,8 +151,7 @@ def evaluate_alert(doc, alert, event):
|
|||
subject = frappe.render_template(alert.subject, context)
|
||||
|
||||
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)
|
||||
|
||||
def get_context(doc):
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ test_records = frappe.get_test_records('Email Alert')
|
|||
|
||||
class TestEmailAlert(unittest.TestCase):
|
||||
def setUp(self):
|
||||
frappe.db.sql("""delete from `tabBulk Email`""")
|
||||
frappe.db.sql("""delete from `tabEmail Queue`""")
|
||||
frappe.set_user("test1@example.com")
|
||||
|
||||
def tearDown(self):
|
||||
|
|
@ -22,14 +22,14 @@ class TestEmailAlert(unittest.TestCase):
|
|||
communication.content = "test"
|
||||
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"}))
|
||||
frappe.db.sql("""delete from `tabBulk Email`""")
|
||||
frappe.db.sql("""delete from `tabEmail Queue`""")
|
||||
|
||||
communication.content = "test 2"
|
||||
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"}))
|
||||
|
||||
def test_condition(self):
|
||||
|
|
@ -39,13 +39,13 @@ class TestEmailAlert(unittest.TestCase):
|
|||
event.starts_on = "2014-06-06 12:00:00"
|
||||
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"}))
|
||||
|
||||
event.event_type = "Public"
|
||||
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"}))
|
||||
|
||||
def test_invalid_condition(self):
|
||||
|
|
@ -72,19 +72,19 @@ class TestEmailAlert(unittest.TestCase):
|
|||
event.starts_on = "2014-06-06 12:00:00"
|
||||
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"}))
|
||||
|
||||
event.subject = "test 1"
|
||||
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"}))
|
||||
|
||||
event.description = "test"
|
||||
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"}))
|
||||
|
||||
def test_date_changed(self):
|
||||
|
|
@ -94,23 +94,23 @@ class TestEmailAlert(unittest.TestCase):
|
|||
event.starts_on = "2014-01-01 12:00:00"
|
||||
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"}))
|
||||
|
||||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True)
|
||||
|
||||
# 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"}))
|
||||
|
||||
event.starts_on = frappe.utils.add_days(frappe.utils.nowdate(), 2) + " 12:00:00"
|
||||
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"}))
|
||||
|
||||
frappe.utils.scheduler.trigger(frappe.local.site, "daily", now=True)
|
||||
|
||||
# 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"}))
|
||||
|
|
|
|||
0
frappe/email/doctype/email_queue/__init__.py
Normal file
0
frappe/email/doctype/email_queue/__init__.py
Normal file
|
|
@ -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) {
|
||||
if (frm.doc.status==="Not Sent") {
|
||||
frm.add_custom_button("Send Now", function() {
|
||||
308
frappe/email/doctype/email_queue/email_queue.json
Normal file
308
frappe/email/doctype/email_queue/email_queue.json
Normal file
|
|
@ -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
|
||||
import frappe
|
||||
|
||||
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
|
||||
|
||||
@frappe.whitelist()
|
||||
def retry_sending(name):
|
||||
doc = frappe.get_doc("Bulk Email", name)
|
||||
doc = frappe.get_doc("Email Queue", name)
|
||||
if doc and doc.status == "Error":
|
||||
doc.status = "Not Sent"
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
@frappe.whitelist()
|
||||
def send_now(name):
|
||||
doc = frappe.get_doc("Bulk Email", name)
|
||||
doc = frappe.get_doc("Email Queue", name)
|
||||
send_one(doc, now=True)
|
||||
|
||||
def on_doctype_update():
|
||||
"""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) {
|
||||
colour = {'Sent': 'green', 'Sending': 'blue', 'Not Sent': 'grey', 'Error': 'red', 'Expired': 'orange'};
|
||||
return [__(doc.status), colour[doc.status], "status,=," + doc.status];
|
||||
12
frappe/email/doctype/email_queue/test_email_queue.py
Normal file
12
frappe/email/doctype/email_queue/test_email_queue.py
Normal file
|
|
@ -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 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,
|
||||
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,
|
||||
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 sender: Email sender.
|
||||
|
|
@ -28,18 +28,18 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc
|
|||
:param message: Email message.
|
||||
:param reference_doctype: Reference DocType 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 attachments: Attachments to be sent.
|
||||
: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 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 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:
|
||||
unsubscribe_method = "/api/method/frappe.email.bulk.unsubscribe"
|
||||
unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe"
|
||||
|
||||
if not recipients:
|
||||
return
|
||||
|
|
@ -54,7 +54,7 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc
|
|||
if not sender or sender == "Administrator":
|
||||
sender = email_account.default_sender
|
||||
|
||||
check_bulk_limit(recipients)
|
||||
check_email_limit(recipients)
|
||||
|
||||
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(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,
|
||||
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.priority = bulk_priority
|
||||
e.priority = send_priority
|
||||
|
||||
try:
|
||||
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.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
|
||||
smtp_server = SMTPServer()
|
||||
|
||||
|
|
@ -147,14 +147,14 @@ def check_bulk_limit(recipients):
|
|||
or frappe.flags.in_test):
|
||||
|
||||
# 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]
|
||||
|
||||
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,
|
||||
email, recipients, expose_recipients, show_as_cc,
|
||||
|
|
@ -241,21 +241,21 @@ def return_unsubscribed_page(email, doctype, name):
|
|||
def flush(from_test=False):
|
||||
"""flush email queue, every time: called from scheduler"""
|
||||
# additional check
|
||||
check_bulk_limit([])
|
||||
check_email_limit([])
|
||||
|
||||
auto_commit = not from_test
|
||||
if frappe.are_emails_muted():
|
||||
msgprint(_("Emails are muted"))
|
||||
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)
|
||||
|
||||
smtpserver = SMTPServer()
|
||||
|
||||
for i in xrange(500):
|
||||
# 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)
|
||||
order by priority desc, creation asc
|
||||
limit 1''', { 'now': now_datetime() }, as_dict=True)
|
||||
|
|
@ -272,15 +272,15 @@ def flush(from_test=False):
|
|||
# frappe.db.commit()
|
||||
|
||||
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':
|
||||
# rollback to release lock and return
|
||||
frappe.db.rollback()
|
||||
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)
|
||||
|
||||
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.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)
|
||||
|
||||
if email.communication:
|
||||
|
|
@ -305,7 +305,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False):
|
|||
JobTimeoutException):
|
||||
|
||||
# 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)
|
||||
|
||||
if email.communication:
|
||||
|
|
@ -317,7 +317,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False):
|
|||
except Exception, e:
|
||||
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)
|
||||
|
||||
if email.communication:
|
||||
|
|
@ -328,11 +328,11 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False):
|
|||
|
||||
else:
|
||||
# log to scheduler log
|
||||
log('frappe.email.bulk.flush', unicode(e))
|
||||
log('frappe.email.queue.flush', unicode(e))
|
||||
|
||||
def clear_outbox():
|
||||
"""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""")
|
||||
|
||||
def prevent_bulk_email_delete(doc, method):
|
||||
|
|
@ -124,7 +124,7 @@ doc_events = {
|
|||
|
||||
scheduler_events = {
|
||||
"all": [
|
||||
"frappe.email.bulk.flush",
|
||||
"frappe.email.queue.flush",
|
||||
"frappe.email.doctype.email_account.email_account.pull",
|
||||
"frappe.email.doctype.email_account.email_account.notify_unreplied",
|
||||
"frappe.utils.error.collect_error_snapshots",
|
||||
|
|
@ -132,7 +132,7 @@ scheduler_events = {
|
|||
'frappe.model.utils.list_settings.sync_list_settings'
|
||||
],
|
||||
"daily": [
|
||||
"frappe.email.bulk.clear_outbox",
|
||||
"frappe.email.queue.clear_outbox",
|
||||
"frappe.desk.notifications.clear_notifications",
|
||||
"frappe.core.doctype.scheduler_log.scheduler_log.set_old_logs_as_seen",
|
||||
"frappe.desk.doctype.event.event.send_event_digest",
|
||||
|
|
|
|||
|
|
@ -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_doctype("File") # 2015-10-19
|
||||
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("delete from `tabDocField` where parent='0'")
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ import frappe
|
|||
|
||||
def execute():
|
||||
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:
|
||||
if e.args[0] not in (1054, 1060):
|
||||
raise
|
||||
|
||||
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:
|
||||
if e.args[0] not in (1054, 1060):
|
||||
raise
|
||||
frappe.reload_doctype("Bulk Email")
|
||||
frappe.reload_doctype("Email Queue")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ def execute():
|
|||
("desk", ("feed", "event", "event_role", "todo", "note")),
|
||||
("custom", ("custom_field", "custom_script", "customize_form",
|
||||
"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")),
|
||||
("print", ("letter_head", "print_format", "print_settings"))
|
||||
)
|
||||
|
|
|
|||
4
frappe/patches/v7_0/rename_bulk_email_to_email_queue.py
Normal file
4
frappe/patches/v7_0/rename_bulk_email_to_email_queue.py
Normal file
|
|
@ -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
|
||||
|
||||
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(),
|
||||
page_name, _("View it in your browser"))
|
||||
|
||||
from frappe.email.bulk import send
|
||||
from frappe.email.queue import send
|
||||
|
||||
send(recipients=recipients,
|
||||
subject = _("New comment on {0} {1}").format(doc.doctype, doc.name),
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@ class TestDB(unittest.TestCase):
|
|||
|
||||
def test_multiple_queries(self):
|
||||
# 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):
|
||||
def setUp(self):
|
||||
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):
|
||||
from frappe.email import sendmail
|
||||
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'],
|
||||
sender="admin@example.com",
|
||||
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):
|
||||
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)
|
||||
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):
|
||||
self.test_bulk()
|
||||
from frappe.email.bulk import flush
|
||||
self.test_email_queue()
|
||||
from frappe.email.queue import flush
|
||||
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):
|
||||
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)
|
||||
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):
|
||||
from frappe.email.bulk import unsubscribe, send
|
||||
from frappe.email.queue import unsubscribe, send
|
||||
unsubscribe(doctype="User", name="Administrator", email="test@example.com")
|
||||
|
||||
self.assertTrue(frappe.db.get_value("Email Unsubscribe",
|
||||
{"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'],
|
||||
sender="admin@example.com",
|
||||
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 (?)
|
||||
|
||||
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)
|
||||
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'])
|
||||
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_bulk_limit(self):
|
||||
from frappe.email.bulk import send, BulkLimitCrossedError
|
||||
self.assertRaises(BulkLimitCrossedError, send,
|
||||
def test_email_queue_limit(self):
|
||||
from frappe.email.queue import send, EmailLimitCrossedError
|
||||
self.assertRaises(EmailLimitCrossedError, send,
|
||||
recipients=['test@example.com']*1000,
|
||||
sender="admin@example.com",
|
||||
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):
|
||||
import re
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue