Sfoglia il codice sorgente

BCC in Emails (#4377)

* added blank carbon copy

* [FEAT] BCC in emails

* removed test_communication, fixed comment

* fixed codacy
version-14
Achilles Rasquinha 7 anni fa
committed by Faris Ansari
parent
commit
b5c4278341
7 ha cambiato i file con 166 aggiunte e 46 eliminazioni
  1. +2
    -2
      frappe/__init__.py
  2. +80
    -21
      frappe/core/doctype/communication/communication.json
  3. +4
    -4
      frappe/core/doctype/communication/communication.py
  4. +57
    -11
      frappe/core/doctype/communication/email.py
  5. +7
    -4
      frappe/email/email_body.py
  6. +8
    -2
      frappe/email/queue.py
  7. +8
    -2
      frappe/public/js/frappe/views/communication.js

+ 2
- 2
frappe/__init__.py Vedi File

@@ -378,7 +378,7 @@ def sendmail(recipients=[], sender="", subject="No Subject", message="No Message
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=[], message_id=None, in_reply_to=None, send_after=None, expose_recipients=None,
cc=[], bcc=[], message_id=None, in_reply_to=None, send_after=None, expose_recipients=None,
send_priority=1, communication=None, retry=1, now=None, read_receipt=None, is_notification=False,
inline_images=None, template=None, args=None, header=None):
"""Send email using user's default **Email Account** or global default **Email Account**.
@@ -426,7 +426,7 @@ def sendmail(recipients=[], sender="", subject="No Subject", message="No Message
subject=subject, message=message, text_content=text_content,
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, message_id=message_id, in_reply_to=in_reply_to,
attachments=attachments, reply_to=reply_to, cc=cc, bcc=bcc, message_id=message_id, in_reply_to=in_reply_to,
send_after=send_after, expose_recipients=expose_recipients, send_priority=send_priority,
communication=communication, now=now, read_receipt=read_receipt, is_notification=is_notification,
inline_images=inline_images, header=header)


+ 80
- 21
frappe/core/doctype/communication/communication.json Vedi File

@@ -15,6 +15,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -43,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -73,6 +75,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -104,6 +107,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -134,6 +138,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -162,6 +167,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -192,6 +198,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -223,6 +230,39 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.communication_medium===\"Email\"",
"fieldname": "bcc",
"fieldtype": "Code",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "BCC",
"length": 0,
"no_copy": 0,
"options": "Email",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -252,6 +292,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -283,6 +324,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -311,6 +353,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -340,6 +383,7 @@
"width": "400"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -369,6 +413,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -398,6 +443,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -429,6 +475,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -459,6 +506,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -487,6 +535,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -518,6 +567,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -548,6 +598,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -576,6 +627,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -605,6 +657,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -634,6 +687,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -662,6 +716,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -691,6 +746,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -720,6 +776,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -750,6 +807,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -780,6 +838,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -810,6 +869,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -841,6 +901,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -871,6 +932,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -901,6 +963,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -929,6 +992,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -959,6 +1023,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -989,6 +1054,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1019,6 +1085,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1049,6 +1116,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1079,6 +1147,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1109,6 +1178,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1138,6 +1208,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1166,6 +1237,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1195,6 +1267,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1224,6 +1297,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1253,6 +1327,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1283,6 +1358,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1312,6 +1388,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1342,6 +1419,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1371,6 +1449,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1411,7 +1490,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-03-29 23:06:16.469149",
"modified": "2017-10-25 12:53:49.547620",
"modified_by": "Administrator",
"module": "Core",
"name": "Communication",
@@ -1477,26 +1556,6 @@
"submit": 0,
"user_permission_doctypes": "[\"Email Account\"]",
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Super Email User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 0
}
],
"quick_entry": 0,


+ 4
- 4
frappe/core/doctype/communication/communication.py Vedi File

@@ -189,7 +189,7 @@ class Communication(Document):
self.notify(print_html, print_format, attachments, recipients)

def notify(self, print_html=None, print_format=None, attachments=None,
recipients=None, cc=None, fetched_from_email_account=False):
recipients=None, cc=None, bcc=None,fetched_from_email_account=False):
"""Calls a delayed task 'sendmail' that enqueus email in Email Queue queue

:param print_html: Send given value as HTML attachment
@@ -200,13 +200,13 @@ class Communication(Document):
:param fetched_from_email_account: True when pulling email, the notification shouldn't go to the main recipient

"""
notify(self, print_html, print_format, attachments, recipients, cc,
notify(self, print_html, print_format, attachments, recipients, cc, bcc,
fetched_from_email_account)

def _notify(self, print_html=None, print_format=None, attachments=None,
recipients=None, cc=None):
recipients=None, cc=None, bcc=None):

_notify(self, print_html, print_format, attachments, recipients, cc)
_notify(self, print_html, print_format, attachments, recipients, cc, bcc)

def bot_reply(self):
if self.comment_type == 'Bot' and self.communication_type == 'Chat':


+ 57
- 11
frappe/core/doctype/communication/email.py Vedi File

@@ -22,7 +22,7 @@ from frappe.utils.background_jobs import enqueue
@frappe.whitelist()
def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent",
sender=None, sender_full_name=None, recipients=None, communication_medium="Email", send_email=False,
print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, cc=None, flags=None,read_receipt=None):
print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, cc=None, bcc=None, flags=None,read_receipt=None):
"""Make a new communication.

:param doctype: Reference DocType.
@@ -58,6 +58,7 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received =
"sender_full_name":sender_full_name,
"recipients": recipients,
"cc": cc or None,
"bcc": bcc or None,
"communication_medium": communication_medium,
"sent_or_received": sent_or_received,
"reference_doctype": doctype,
@@ -102,10 +103,13 @@ def validate_email(doc):
for email in split_emails(doc.cc):
validate_email_add(email, throw=True)

for email in split_emails(doc.bcc):
validate_email_add(email, throw=True)

# validate sender

def notify(doc, print_html=None, print_format=None, attachments=None,
recipients=None, cc=None, fetched_from_email_account=False):
recipients=None, cc=None, bcc=None, fetched_from_email_account=False):
"""Calls a delayed task 'sendmail' that enqueus email in Email Queue queue

:param print_html: Send given value as HTML attachment
@@ -113,10 +117,11 @@ def notify(doc, print_html=None, print_format=None, attachments=None,
:param attachments: A list of filenames that should be attached when sending this email
:param recipients: Email recipients
:param cc: Send email as CC to
:param bcc: Send email as BCC to
:param fetched_from_email_account: True when pulling email, the notification shouldn't go to the main recipient

"""
recipients, cc = get_recipients_and_cc(doc, recipients, cc,
recipients, cc, bcc = get_recipients_cc_and_bcc(doc, recipients, cc, bcc,
fetched_from_email_account=fetched_from_email_account)

if not recipients:
@@ -127,16 +132,16 @@ def notify(doc, print_html=None, print_format=None, attachments=None,
if frappe.flags.in_test:
# for test cases, run synchronously
doc._notify(print_html=print_html, print_format=print_format, attachments=attachments,
recipients=recipients, cc=cc)
recipients=recipients, cc=cc, bcc=None)
else:
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,
recipients=recipients, cc=cc, lang=frappe.local.lang, session=frappe.local.session)
recipients=recipients, cc=cc, bcc=bcc, lang=frappe.local.lang, session=frappe.local.session)

def _notify(doc, print_html=None, print_format=None, attachments=None,
recipients=None, cc=None):
recipients=None, cc=None, bcc=None):

prepare_to_notify(doc, print_html, print_format, attachments)

@@ -148,6 +153,7 @@ def _notify(doc, print_html=None, print_format=None, attachments=None,
frappe.sendmail(
recipients=(recipients or []),
cc=(cc or []),
bcc=(bcc or []),
expose_recipients="header",
sender=doc.sender,
reply_to=doc.incoming_email_account,
@@ -190,7 +196,7 @@ def update_parent_mins_to_first_response(doc):
parent.run_method('notify_communication', doc)
parent.notify_update()

def get_recipients_and_cc(doc, recipients, cc, fetched_from_email_account=False):
def get_recipients_cc_and_bcc(doc, recipients, cc, bcc, fetched_from_email_account=False):
doc.all_email_addresses = []
doc.sent_email_addresses = []
doc.previous_email_sender = None
@@ -201,6 +207,9 @@ def get_recipients_and_cc(doc, recipients, cc, fetched_from_email_account=False)
if not cc:
cc = get_cc(doc, recipients, fetched_from_email_account=fetched_from_email_account)

if not bcc:
bcc = get_bcc(doc, recipients, fetched_from_email_account=fetched_from_email_account)

if fetched_from_email_account:
# email was already sent to the original recipient by the sender's email service
original_recipients, recipients = recipients, []
@@ -216,10 +225,13 @@ def get_recipients_and_cc(doc, recipients, cc, fetched_from_email_account=False)
# don't cc to people who already received the mail from sender's email service
cc = list(set(cc) - set(original_cc) - set(original_recipients))

original_bcc = split_emails(doc.bcc)
bcc = list(set(bcc) - set(original_bcc) - set(original_recipients))

if 'Administrator' in recipients:
recipients.remove('Administrator')

return recipients, cc
return recipients, cc, bcc

def prepare_to_notify(doc, print_html=None, print_format=None, attachments=None):
"""Prepare to make multipart MIME Email
@@ -345,6 +357,34 @@ def get_cc(doc, recipients=None, fetched_from_email_account=False):

return cc

def get_bcc(doc, recipients=None, fetched_from_email_account=False):
"""Build a list of email addresses for BCC"""
bcc = split_emails(doc.bcc)

if doc.reference_doctype and doc.reference_name:
if fetched_from_email_account:
bcc.append(get_owner_email(doc))
bcc += get_assignees(doc)

if getattr(doc, "send_me_a_copy", False) and doc.sender not in bcc:
bcc.append(doc.sender)

if bcc:
exclude = []
exclude += [d[0] for d in frappe.db.get_all("User", ["name"], {"thread_notify": 0}, as_list=True)]
exclude += [(parse_addr(email)[1] or "").lower() for email in recipients]

if fetched_from_email_account:
# exclude sender when pulling email
exclude += [parse_addr(doc.sender)[1]]

if doc.reference_doctype and doc.reference_name:
exclude += [d[0] for d in frappe.db.get_all("Email Unsubscribe", ["email"],
{"reference_doctype": doc.reference_doctype, "reference_name": doc.reference_name}, as_list=True)]

bcc = filter_email_list(doc, bcc, exclude, is_bcc=True)

return bcc

def add_attachments(name, attachments):
'''Add attachments to the given Communiction'''
@@ -360,7 +400,7 @@ def add_attachments(name, attachments):
save_url(attach.file_url, attach.file_name, "Communication", name,
"Home/Attachments", attach.is_private)

def filter_email_list(doc, email_list, exclude, is_cc=False):
def filter_email_list(doc, email_list, exclude, is_cc=False, is_bcc=False):
# temp variables
filtered = []
email_address_list = []
@@ -382,6 +422,11 @@ def filter_email_list(doc, email_list, exclude, is_cc=False):
# don't send to disabled users
continue

if is_bcc:
is_user_enabled = frappe.db.get_value("User", email_address, "enabled")
if is_user_enabled==0:
continue

# make sure of case-insensitive uniqueness of email address
if email_address not in email_address_list:
# append the full email i.e. "Human <human@example.com>"
@@ -416,7 +461,7 @@ def get_attach_link(doc, print_format):
})

def sendmail(communication_name, print_html=None, print_format=None, attachments=None,
recipients=None, cc=None, lang=None, session=None):
recipients=None, cc=None, bcc=None, lang=None, session=None):
try:

if lang:
@@ -432,7 +477,7 @@ def sendmail(communication_name, print_html=None, print_format=None, attachments
try:
communication = frappe.get_doc("Communication", communication_name)
communication._notify(print_html=print_html, print_format=print_format, attachments=attachments,
recipients=recipients, cc=cc)
recipients=recipients, cc=cc, bcc=bcc)

except MySQLdb.OperationalError as e:
# deadlock, try again
@@ -453,6 +498,7 @@ def sendmail(communication_name, print_html=None, print_format=None, attachments
"attachments": attachments,
"recipients": recipients,
"cc": cc,
"bcc": bcc,
"lang": lang
}))
frappe.logger(__name__).error(traceback)


+ 7
- 4
frappe/email/email_body.py Vedi File

@@ -15,7 +15,7 @@ from email.header import Header

def get_email(recipients, sender='', msg='', subject='[No Subject]',
text_content = None, footer=None, print_html=None, formatted=None, attachments=None,
content=None, reply_to=None, cc=[], email_account=None, expose_recipients=None,
content=None, reply_to=None, cc=[], bcc=[], email_account=None, expose_recipients=None,
inline_images=[], header=None):
""" Prepare an email with the following format:
- multipart/mixed
@@ -27,7 +27,7 @@ def get_email(recipients, sender='', msg='', subject='[No Subject]',
- attachment
"""
content = content or msg
emailobj = EMail(sender, recipients, subject, reply_to=reply_to, cc=cc, email_account=email_account, expose_recipients=expose_recipients)
emailobj = EMail(sender, recipients, subject, reply_to=reply_to, cc=cc, bcc=bcc, email_account=email_account, expose_recipients=expose_recipients)

if not content.strip().startswith("<"):
content = markdown(content)
@@ -51,7 +51,7 @@ class EMail:
Also provides a clean way to add binary `FileData` attachments
Also sets all messages as multipart/alternative for cleaner reading in text-only clients
"""
def __init__(self, sender='', recipients=(), subject='', alternative=0, reply_to=None, cc=(), email_account=None, expose_recipients=None):
def __init__(self, sender='', recipients=(), subject='', alternative=0, reply_to=None, cc=(), bcc=(), email_account=None, expose_recipients=None):
from email import charset as Charset
Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8')

@@ -72,6 +72,7 @@ class EMail:
self.msg_alternative = MIMEMultipart('alternative')
self.msg_root.attach(self.msg_alternative)
self.cc = cc or []
self.bcc = bcc or []
self.html_set = False

self.email_account = email_account or get_outgoing_email_account(sender=sender)
@@ -176,8 +177,9 @@ class EMail:

self.recipients = [strip(r) for r in self.recipients]
self.cc = [strip(r) for r in self.cc]
self.bcc = [strip(r) for r in self.bcc]

for e in self.recipients + (self.cc or []):
for e in self.recipients + (self.cc or []) + (self.bcc or []):
validate_email_add(e, True)

def replace_sender(self):
@@ -207,6 +209,7 @@ class EMail:
"To": ', '.join(self.recipients) if self.expose_recipients=="header" else "<!--recipient-->",
"Date": email.utils.formatdate(),
"Reply-To": self.reply_to if self.reply_to else None,
"Bcc": ', '.join(self.bcc) if self.bcc else None,
"CC": ', '.join(self.cc) if self.cc and self.expose_recipients=="header" else None,
'X-Frappe-Site': get_url(),
}


+ 8
- 2
frappe/email/queue.py Vedi File

@@ -21,7 +21,7 @@ class EmailLimitCrossedError(frappe.ValidationError): pass

def send(recipients=None, sender=None, subject=None, message=None, text_content=None, reference_doctype=None,
reference_name=None, unsubscribe_method=None, unsubscribe_params=None, unsubscribe_message=None,
attachments=None, reply_to=None, cc=[], message_id=None, in_reply_to=None, send_after=None,
attachments=None, reply_to=None, cc=[], bcc=[], message_id=None, in_reply_to=None, send_after=None,
expose_recipients=None, send_priority=1, communication=None, now=False, read_receipt=None,
queue_separately=False, is_notification=False, add_unsubscribe_link=1, inline_images=None,
header=None):
@@ -61,6 +61,9 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content=
if isinstance(cc, string_types):
cc = split_emails(cc)

if isinstance(bcc, string_types):
bcc = split_emails(bcc)

if isinstance(send_after, int):
send_after = add_days(nowdate(), send_after)

@@ -112,6 +115,7 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content=
attachments=attachments,
reply_to=reply_to,
cc=cc,
bcc=bcc,
message_id=message_id,
in_reply_to=in_reply_to,
send_after=send_after,
@@ -174,6 +178,7 @@ def get_email_queue(recipients, sender, subject, **kwargs):
attachments=kwargs.get('attachments'),
reply_to=kwargs.get('reply_to'),
cc=kwargs.get('cc'),
bcc=kwargs.get('bcc'),
email_account=kwargs.get('email_account'),
expose_recipients=kwargs.get('expose_recipients'),
inline_images=kwargs.get('inline_images'),
@@ -194,7 +199,7 @@ def get_email_queue(recipients, sender, subject, **kwargs):
frappe.log_error('Invalid Email ID Sender: {0}, Recipients: {1}'.format(mail.sender,
', '.join(mail.recipients)), 'Email Not Sent')

e.set_recipients(recipients + kwargs.get('cc', []))
e.set_recipients(recipients + kwargs.get('cc', []) + kwargs.get('bcc', []))
e.reference_doctype = kwargs.get('reference_doctype')
e.reference_name = kwargs.get('reference_name')
e.add_unsubscribe_link = kwargs.get("add_unsubscribe_link")
@@ -204,6 +209,7 @@ def get_email_queue(recipients, sender, subject, **kwargs):
e.communication = kwargs.get('communication')
e.send_after = kwargs.get('send_after')
e.show_as_cc = ",".join(kwargs.get('cc', []))
e.show_as_bcc = ",".join(kwargs.get('bcc', []))
e.insert(ignore_permissions=True)

return e


+ 8
- 2
frappe/public/js/frappe/views/communication.js Vedi File

@@ -48,8 +48,9 @@ frappe.views.CommunicationComposer = Class.extend({
get_fields: function() {
var fields= [
{label:__("To"), fieldtype:"Data", reqd: 0, fieldname:"recipients",length:524288},
{fieldtype: "Section Break", collapsible: 1, label: __("CC & Standard Reply")},
{fieldtype: "Section Break", collapsible: 1, label: __("CC, BCC & Standard Reply")},
{label:__("CC"), fieldtype:"Data", fieldname:"cc", length:524288},
{label:__("BCC"), fieldtype:"Data", fieldname:"bcc", length:524288},
{label:__("Standard Reply"), fieldtype:"Link", options:"Standard Reply",
fieldname:"standard_reply"},
{fieldtype: "Section Break"},
@@ -109,6 +110,7 @@ frappe.views.CommunicationComposer = Class.extend({

this.dialog.fields_dict.recipients.set_value(this.recipients || '');
this.dialog.fields_dict.cc.set_value(this.cc || '');
this.dialog.fields_dict.bcc.set_value(this.bcc || '');

if(this.dialog.fields_dict.sender) {
this.dialog.fields_dict.sender.set_value(this.sender || '');
@@ -123,6 +125,7 @@ frappe.views.CommunicationComposer = Class.extend({
if(!this.forward && !this.recipients && this.last_email) {
this.recipients = this.last_email.sender;
this.cc = this.last_email.cc;
this.bcc = this.last_email.bcc;
}

if(!this.forward && !this.recipients) {
@@ -446,6 +449,7 @@ frappe.views.CommunicationComposer = Class.extend({
// concat in cc
if ( form_values[df.fieldname] ) {
form_values.cc = ( form_values.cc ? (form_values.cc + ", ") : "" ) + df.fieldname;
form_values.bcc = ( form_values.bcc ? (form_values.bcc + ", ") : "" ) + df.fieldname;
}

delete form_values[df.fieldname];
@@ -484,6 +488,7 @@ frappe.views.CommunicationComposer = Class.extend({
args: {
recipients: form_values.recipients,
cc: form_values.cc,
bcc: form_values.bcc,
subject: form_values.subject,
content: form_values.content,
doctype: me.doc.doctype,
@@ -594,7 +599,8 @@ frappe.views.CommunicationComposer = Class.extend({
var me = this;
[
this.dialog.fields_dict.recipients.input,
this.dialog.fields_dict.cc.input
this.dialog.fields_dict.cc.input,
this.dialog.fields_dict.bcc.input
].map(function(input) {
me.setup_awesomplete_for_input(input);
});


Caricamento…
Annulla
Salva