def test_get_email_account(self): existing_email_accounts = frappe.get_all("Email Account", fields=[ "name", "enable_outgoing", "default_outgoing", "append_to" ]) unset_details = { "enable_outgoing": 0, "default_outgoing": 0, "append_to": None } for email_account in existing_email_accounts: frappe.db.set_value("Email Account", email_account["name"], unset_details) # remove mail_server config so that [email protected] is not created mail_server = frappe.conf.get("mail_server") del frappe.conf["mail_server"] frappe.local.outgoing_email_account = {} frappe.local.outgoing_email_account = {} # lowest preference given to email account with default incoming enabled create_email_account( email_id="*****@*****.**", password="******", enable_outgoing=1, default_outgoing=1, ) self.assertEqual(get_outgoing_email_account().email_id, "*****@*****.**") frappe.local.outgoing_email_account = {} # highest preference given to email account with append_to matching create_email_account( email_id="*****@*****.**", password="******", enable_outgoing=1, default_outgoing=1, append_to="Blog Post", ) self.assertEqual( get_outgoing_email_account(append_to="Blog Post").email_id, "*****@*****.**") # add back the mail_server frappe.conf["mail_server"] = mail_server for email_account in existing_email_accounts: set_details = { "enable_outgoing": email_account["enable_outgoing"], "default_outgoing": email_account["default_outgoing"], "append_to": email_account["append_to"], } frappe.db.set_value("Email Account", email_account["name"], set_details)
def get_formatted_html(subject, message, footer=None, print_html=None, email_account=None, header=None): if not email_account: email_account = get_outgoing_email_account(False) rendered_email = frappe.get_template( "templates/emails/standard.html").render({ "header": get_header(header), "content": message, "signature": get_signature(email_account), "footer": get_footer(email_account, footer), "title": subject, "print_html": print_html, "subject": subject }) sanitized_html = scrub_urls(rendered_email) transformed_html = inline_style_in_html(sanitized_html) return transformed_html
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') if isinstance(recipients, string_types): recipients = recipients.replace(';', ',').replace('\n', '') recipients = split_emails(recipients) # remove null recipients = filter(None, (strip(r) for r in recipients)) self.sender = sender self.reply_to = reply_to or sender self.recipients = recipients self.subject = subject self.expose_recipients = expose_recipients self.msg_root = MIMEMultipart('mixed') 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)
def get_formatted_html(subject, message, footer=None, print_html=None, email_account=None, header=None, unsubscribe_link=None, sender=None, with_container=False): if not email_account: email_account = get_outgoing_email_account(False, sender=sender) signature = None if "<!-- signature-included -->" not in message: signature = get_signature(email_account) rendered_email = frappe.get_template("templates/emails/standard.html").render({ "brand_logo": get_brand_logo(email_account) if with_container or header else None, "with_container": with_container, "site_url": get_url(), "header": get_header(header), "content": message, "signature": signature, "footer": get_footer(email_account, footer), "title": subject, "print_html": print_html, "subject": subject }) html = scrub_urls(rendered_email) if unsubscribe_link: html = html.replace("<!--unsubscribe link here-->", unsubscribe_link.html) html = inline_style_in_html(html) return html
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') if isinstance(recipients, string_types): recipients = recipients.replace(';', ',').replace('\n', '') recipients = split_emails(recipients) # remove null recipients = filter(None, (strip(r) for r in recipients)) self.sender = sender self.reply_to = reply_to or sender self.recipients = recipients self.subject = subject self.expose_recipients = expose_recipients self.msg_root = MIMEMultipart('mixed') 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)
def get_formatted_html(subject, message, footer=None, print_html=None, email_account=None): message = scrub_urls(message) if not email_account: email_account = get_outgoing_email_account(False) rendered_email = frappe.get_template( "templates/emails/standard.html").render({ "content": message, "signature": get_signature(email_account), "footer": get_footer(email_account, footer), "title": subject, "print_html": print_html, "subject": subject }) return rendered_email
def on_update(self): email_account = get_outgoing_email_account(True) if email_account.enable_outgoing == 1: frappe.sendmail( recipients="[email protected], [email protected]", subject="Error " + self.titul + " Actualitzat: " + self.estat, message="http://13.80.115.15/desk#Form/Errors/" + self.name + "\n\n\n\n" + self.descripcio, sender="*****@*****.**")
def get_formatted_html(subject, message, footer=None, print_html=None, email_account=None): if not email_account: email_account = get_outgoing_email_account(False) rendered_email = frappe.get_template("templates/emails/standard.html").render({ "content": message, "signature": get_signature(email_account), "footer": get_footer(email_account, footer), "title": subject, "print_html": print_html, "subject": subject }) return scrub_urls(rendered_email)
def get_formatted_html(subject, message, footer=None, print_html=None): # imported here to avoid cyclic import message = scrub_urls(message) email_account = get_outgoing_email_account(False) rendered_email = frappe.get_template("templates/emails/standard.html").render( { "content": message, "signature": get_signature(email_account), "footer": get_footer(email_account, footer), "title": subject, "print_html": print_html, "subject": subject, } ) return rendered_email
def get_footer(footer=None): """append a footer (signature)""" footer = footer or "" email_account = get_outgoing_email_account(False) if email_account and email_account.add_signature and email_account.signature: footer += email_account.signature if email_account and email_account.footer: footer += email_account.footer else: for default_mail_footer in frappe.get_hooks("default_mail_footer"): footer += default_mail_footer footer += "<!--unsubscribe link here-->" return footer
def validate(self): """validate the email ids""" from frappe.utils import validate_email_add def _validate(email): """validate an email field""" if email and not validate_email_add(email): throw(_("{0} is not a valid email id").format(email), frappe.InvalidEmailAddressError) return email if not self.sender: email_account = get_outgoing_email_account() self.sender = email.utils.formataddr((email_account.name, email_account.get("sender") or email_account.get("email_id"))) self.sender = _validate(strip(self.sender)) self.reply_to = _validate(strip(self.reply_to) or self.sender) self.recipients = [strip(r) for r in self.recipients] self.cc = [strip(r) for r in self.cc] for e in self.recipients + (self.cc or []): _validate(e)
def get_formatted_html(subject, message, footer=None, print_html=None, email_account=None, header=None, unsubscribe_link=None, sender=None): if not email_account: email_account = get_outgoing_email_account(False, sender=sender) rendered_email = frappe.get_template("templates/emails/standard.html").render({ "header": get_header(header), "content": message, "signature": get_signature(email_account), "footer": get_footer(email_account, footer), "title": subject, "print_html": print_html, "subject": subject }) html = scrub_urls(rendered_email) if unsubscribe_link: html = html.replace("<!--unsubscribe link here-->", unsubscribe_link.html) html = inline_style_in_html(html) return html
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") if isinstance(recipients, string_types): recipients = recipients.replace(";", ",").replace("\n", "") recipients = split_emails(recipients) # remove null recipients = filter(None, (strip(r) for r in recipients)) self.sender = sender self.reply_to = reply_to or sender self.recipients = recipients self.subject = subject self.expose_recipients = expose_recipients self.msg_root = MIMEMultipart("mixed", policy=policy.SMTPUTF8) self.msg_alternative = MIMEMultipart("alternative", policy=policy.SMTPUTF8) 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)
def validate(self): """validate the email ids""" from frappe.utils import validate_email_add def _validate(email): """validate an email field""" if email and not validate_email_add(email): throw( _("{0} is not a valid email id").format(email), frappe.InvalidEmailAddressError) return email if not self.sender: email_account = get_outgoing_email_account() self.sender = "{0} <{1}>".format(email_account.name, email_account.email_id) self.sender = _validate(self.sender) self.reply_to = _validate(self.reply_to) for e in self.recipients + (self.cc or []): _validate(e.strip())
def send(recipients=None, sender=None, doctype='User', email_field='email', subject='[No Subject]', message='[No Content]', ref_doctype=None, ref_docname=None, add_unsubscribe_link=True, attachments=None, reply_to=None): def is_unsubscribed(rdata): if not rdata: return 1 return cint(rdata.unsubscribed) def check_bulk_limit(new_mails): this_month = frappe.db.sql( """select count(*) from `tabBulk Email` where month(creation)=month(%s)""" % nowdate())[0][0] # No limit for own email settings smtp_server = SMTPServer() if smtp_server.email_account and not getattr( smtp_server.email_account, "from_site_config", False) or frappe.flags.in_test: monthly_bulk_mail_limit = frappe.conf.get( 'monthly_bulk_mail_limit') or 500 if (this_month + len(recipients)) > monthly_bulk_mail_limit: throw( _("Bulk email limit {0} crossed").format( monthly_bulk_mail_limit), BulkLimitCrossedError) def update_message(formatted, doc, add_unsubscribe_link): updated = formatted if add_unsubscribe_link: unsubscribe_link = """<div style="padding: 7px; border-top: 1px solid #aaa; margin-top: 17px;"> <small><a href="%s/?%s"> Unsubscribe</a> from this list.</small></div>""" % ( get_url(), urllib.urlencode({ "cmd": "frappe.email.bulk.unsubscribe", "email": doc.get(email_field), "type": doctype, "email_field": email_field })) updated = updated.replace("<!--unsubscribe link here-->", unsubscribe_link) return updated if not recipients: recipients = [] if not sender or sender == "Administrator": email_account = get_outgoing_email_account() sender = email_account.get("sender") or email_account.email_id check_bulk_limit(len(recipients)) formatted = get_formatted_html(subject, message) for r in filter(None, list(set(recipients))): rdata = frappe.db.sql("""select * from `tab%s` where %s=%s""" % (doctype, email_field, '%s'), (r, ), as_dict=1) doc = rdata and rdata[0] or {} if (not add_unsubscribe_link) or (not is_unsubscribed(doc)): # add to queue updated = update_message(formatted, doc, add_unsubscribe_link) try: text_content = html2text(updated) except HTMLParser.HTMLParseError: text_content = "[See html attachment]" add(r, sender, subject, updated, text_content, ref_doctype, ref_docname, attachments, reply_to)
def get_default_sender(self): return get_outgoing_email_account().default_sender
def get_default_sender(self): email_account = get_outgoing_email_account() return email.utils.formataddr((email_account.name, email_account.get("sender") or email_account.get("email_id")))
def prepare_message(email, recipient, recipients_list): message = email.message if not message: return "" # Parse "Email Account" from "Email Sender" email_account = get_outgoing_email_account(raise_exception_not_set=False, sender=email.sender) if frappe.conf.use_ssl and email_account.track_email_status: # Using SSL => Publically available domain => Email Read Reciept Possible message = message.replace( "<!--email open check-->", quopri.encodestring( '<img src="https://{}/api/method/frappe.core.doctype.communication.email.mark_email_as_seen?name={}"/>' .format(frappe.local.site, email.communication).encode()).decode()) else: # No SSL => No Email Read Reciept message = message.replace("<!--email open check-->", quopri.encodestring("".encode()).decode()) if email.add_unsubscribe_link and email.reference_doctype: # is missing the check for unsubscribe message but will not add as there will be no unsubscribe url unsubscribe_url = get_unsubcribed_url(email.reference_doctype, email.reference_name, recipient, email.unsubscribe_method, email.unsubscribe_params) message = message.replace( "<!--unsubscribe url-->", quopri.encodestring(unsubscribe_url.encode()).decode()) if email.expose_recipients == "header": pass else: if email.expose_recipients == "footer": if isinstance(email.show_as_cc, string_types): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join( [e for e in email_sent_to if e in email.show_as_cc]) email_sent_to = ", ".join( [e for e in email_sent_to if e not in email.show_as_cc]) if email_sent_cc: email_sent_message = _( "This email was sent to {0} and copied to {1}").format( email_sent_to, email_sent_cc) else: email_sent_message = _("This email was sent to {0}").format( email_sent_to) message = message.replace( "<!--cc message-->", quopri.encodestring(email_sent_message.encode()).decode()) message = message.replace("<!--recipient-->", recipient) message = (message and message.encode('utf8')) or '' message = safe_decode(message) if PY3: from email.policy import SMTPUTF8 message = Parser(policy=SMTPUTF8).parsestr(message) else: message = Parser().parsestr(message) if email.attachments: # On-demand attachments attachments = json.loads(email.attachments) for attachment in attachments: if attachment.get('fcontent'): continue fid = attachment.get("fid") if fid: _file = frappe.get_doc("File", fid) fcontent = _file.get_content() attachment.update({ 'fname': _file.file_name, 'fcontent': fcontent, 'parent': message }) attachment.pop("fid", None) add_attachment(**attachment) elif attachment.get("print_format_attachment") == 1: attachment.pop("print_format_attachment", None) print_format_file = frappe.attach_print(**attachment) print_format_file.update({"parent": message}) add_attachment(**print_format_file) return safe_encode(message.as_string())
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=(), message_id=None, send_after=None, expose_recipients=False, bulk_priority=1): """Add email to sending queue (Bulk Email) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :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 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 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. """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.bulk.unsubscribe" if not recipients: return if isinstance(recipients, basestring): recipients = split_emails(recipients) if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) if not sender or sender == "Administrator": email_account = get_outgoing_email_account() sender = email_account.get("sender") or email_account.email_id check_bulk_limit(recipients) formatted = get_formatted_html(subject, message) try: text_content = html2text(formatted) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"reference_doctype": reference_doctype, "reference_name": reference_name})] unsubscribed += [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"global_unsubscribe": 1})] else: unsubscribed = [] recipients = [r for r in list(set(recipients)) if r and r not in unsubscribed] for email in recipients: email_content = formatted email_text_context = text_content if reference_doctype: unsubscribe_link = get_unsubscribe_link( reference_doctype=reference_doctype, reference_name=reference_name, email=email, recipients=recipients, expose_recipients=expose_recipients, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, unsubscribe_message=unsubscribe_message ) email_content = email_content.replace("<!--unsubscribe link here-->", unsubscribe_link.html) email_text_context += unsubscribe_link.text # add to queue add(email, sender, subject, email_content, email_text_context, reference_doctype, reference_name, attachments, reply_to, cc, message_id, send_after, bulk_priority)
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) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :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 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 """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.bulk.unsubscribe" if not recipients: return if isinstance(recipients, basestring): recipients = split_emails(recipients) if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) email_account = get_outgoing_email_account(True, append_to=reference_doctype) if not sender or sender == "Administrator": sender = email_account.default_sender check_bulk_limit(recipients) formatted = get_formatted_html(subject, message, email_account=email_account) try: text_content = html2text(formatted) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [ d.email for d in frappe.db.get_all( "Email Unsubscribe", "email", { "reference_doctype": reference_doctype, "reference_name": reference_name }) ] unsubscribed += [ d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"global_unsubscribe": 1}) ] else: unsubscribed = [] recipients = [ r for r in list(set(recipients)) if r and r not in unsubscribed ] for email in recipients: email_content = formatted email_text_context = text_content if reference_doctype: unsubscribe_link = get_unsubscribe_link( reference_doctype=reference_doctype, reference_name=reference_name, email=email, recipients=recipients, expose_recipients=expose_recipients, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, unsubscribe_message=unsubscribe_message, show_as_cc=show_as_cc) email_content = email_content.replace( "<!--unsubscribe link here-->", unsubscribe_link.html) email_text_context += unsubscribe_link.text # show as cc cc_message = "" if email in show_as_cc: cc_message = _("This email was sent to you as CC") email_content = email_content.replace("<!-- cc message -->", cc_message) email_text_context = cc_message + "\n" + email_text_context # 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)
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=(), message_id=None, send_after=None): """Add email to sending queue (Bulk Email) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :param message: Email message. :param reference_doctype: Reference DocType of caller document. :param reference_name: Reference name of caller document. :param unsubscribe_method: URL method for unsubscribe. Default is `/api/method/frappe.email.bulk.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 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. """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.bulk.unsubscribe" if not recipients: return if isinstance(recipients, basestring): recipients = recipients.split(",") if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) if not sender or sender == "Administrator": email_account = get_outgoing_email_account() sender = email_account.get("sender") or email_account.email_id check_bulk_limit(recipients) formatted = get_formatted_html(subject, message) try: text_content = html2text(formatted) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"reference_doctype": reference_doctype, "reference_name": reference_name})] else: unsubscribed = [] for email in filter(None, list(set(recipients))): if email not in unsubscribed: email_content = formatted email_text_context = text_content if reference_doctype: unsubscribe_url = get_unsubcribed_url(reference_doctype, reference_name, email, unsubscribe_method, unsubscribe_params) # add to queue email_content = add_unsubscribe_link(email_content, email, reference_doctype, reference_name, unsubscribe_url, unsubscribe_message) email_text_context += "\n" + _("This email was sent to {0}. To unsubscribe click on this link: {1}").format(email, unsubscribe_url) add(email, sender, subject, email_content, email_text_context, reference_doctype, reference_name, attachments, reply_to, cc, message_id, send_after)
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=[], message_id=None, in_reply_to=None, send_after=None, expose_recipients=None, send_priority=1, communication=None, now=False): """Add email to sending queue (Email Queue) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :param message: Email message. :param reference_doctype: Reference DocType of caller document. :param reference_name: Reference name of caller document. :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 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 Email Queue record :param now: Send immediately (don't send in the background) """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe" if not recipients and not cc: return if isinstance(recipients, basestring): recipients = split_emails(recipients) if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) email_account = get_outgoing_email_account(True, append_to=reference_doctype) if not sender or sender == "Administrator": sender = email_account.default_sender check_email_limit(recipients) formatted = get_formatted_html(subject, message, email_account=email_account) try: text_content = html2text(formatted) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"reference_doctype": reference_doctype, "reference_name": reference_name})] unsubscribed += [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"global_unsubscribe": 1})] else: unsubscribed = [] recipients = [r for r in list(set(recipients)) if r and r not in unsubscribed] email_content = formatted email_text_context = text_content if reference_doctype and (unsubscribe_message or reference_doctype=="Newsletter"): unsubscribe_link = get_unsubscribe_message(unsubscribe_message, expose_recipients) email_content = email_content.replace("<!--unsubscribe link here-->", unsubscribe_link.html) email_text_context += unsubscribe_link.text # add to queue email_queue = add(recipients, sender, subject, email_content, email_text_context, reference_doctype, reference_name, attachments, reply_to, cc, message_id, in_reply_to, send_after, send_priority, email_account=email_account, communication=communication, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, expose_recipients=expose_recipients) if now: send_one(email_queue.name, now=True)
def get_default_sender(self): email_account = get_outgoing_email_account() return email.utils.formataddr( (email_account.name, email_account.get("sender") or email_account.get("email_id")))
def prepare_message(email, recipient, recipients_list): message = email.message if not message: return "" # Parse "Email Account" from "Email Sender" email_account = get_outgoing_email_account(raise_exception_not_set=False, sender=email.sender) if frappe.conf.use_ssl and email_account.track_email_status: # Using SSL => Publically available domain => Email Read Reciept Possible message = message.replace("<!--email open check-->", quopri.encodestring('<img src="https://{}/api/method/frappe.core.doctype.communication.email.mark_email_as_seen?name={}"/>'.format(frappe.local.site, email.communication).encode()).decode()) else: # No SSL => No Email Read Reciept message = message.replace("<!--email open check-->", quopri.encodestring("".encode()).decode()) if email.add_unsubscribe_link and email.reference_doctype: # is missing the check for unsubscribe message but will not add as there will be no unsubscribe url unsubscribe_url = get_unsubcribed_url(email.reference_doctype, email.reference_name, recipient, email.unsubscribe_method, email.unsubscribe_params) message = message.replace("<!--unsubscribe url-->", quopri.encodestring(unsubscribe_url.encode()).decode()) if email.expose_recipients == "header": pass else: if email.expose_recipients == "footer": if isinstance(email.show_as_cc, string_types): email.show_as_cc = email.show_as_cc.split(",") email_sent_to = [r.recipient for r in recipients_list] email_sent_cc = ", ".join([e for e in email_sent_to if e in email.show_as_cc]) email_sent_to = ", ".join([e for e in email_sent_to if e not in email.show_as_cc]) if email_sent_cc: email_sent_message = _("This email was sent to {0} and copied to {1}").format(email_sent_to,email_sent_cc) else: email_sent_message = _("This email was sent to {0}").format(email_sent_to) message = message.replace("<!--cc message-->", quopri.encodestring(email_sent_message.encode()).decode()) message = message.replace("<!--recipient-->", recipient) message = (message and message.encode('utf8')) or '' message = safe_decode(message) if not email.attachments: return message # On-demand attachments from email.parser import Parser msg_obj = Parser().parsestr(message) attachments = json.loads(email.attachments) for attachment in attachments: if attachment.get('fcontent'): continue fid = attachment.get("fid") if fid: fname, fcontent = get_file(fid) attachment.update({ 'fname': fname, 'fcontent': fcontent, 'parent': msg_obj }) attachment.pop("fid", None) add_attachment(**attachment) elif attachment.get("print_format_attachment") == 1: attachment.pop("print_format_attachment", None) print_format_file = frappe.attach_print(**attachment) print_format_file.update({"parent": msg_obj}) add_attachment(**print_format_file) return msg_obj.as_string()
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=[], 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, print_letterhead=False): """Add email to sending queue (Email Queue) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :param message: Email message. :param text_content: Text version of email message. :param reference_doctype: Reference DocType of caller document. :param reference_name: Reference name of caller document. :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 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 Email Queue record :param now: Send immediately (don't send in the background) :param queue_separately: Queue each email separately :param is_notification: Marks email as notification so will not trigger notifications from system :param add_unsubscribe_link: Send unsubscribe link in the footer of the Email, default 1. :param inline_images: List of inline images as {"filename", "filecontent"}. All src properties will be replaced with random Content-Id :param header: Append header in email (boolean) """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe" if not recipients and not cc: return if isinstance(recipients, string_types): recipients = split_emails(recipients) 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) email_account = get_outgoing_email_account(True, append_to=reference_doctype, sender=sender) if not sender or sender == "Administrator": sender = email_account.default_sender check_email_limit(recipients) if not text_content: try: text_content = html2text(message) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"reference_doctype": reference_doctype, "reference_name": reference_name})] unsubscribed += [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"global_unsubscribe": 1})] else: unsubscribed = [] recipients = [r for r in list(set(recipients)) if r and r not in unsubscribed] if cc: cc = [r for r in list(set(cc)) if r and r not in unsubscribed] if not recipients and not cc: # Recipients may have been unsubscribed, exit quietly return email_text_context = text_content should_append_unsubscribe = (add_unsubscribe_link and reference_doctype and (unsubscribe_message or reference_doctype=="Newsletter") and add_unsubscribe_link==1) unsubscribe_link = None if should_append_unsubscribe: unsubscribe_link = get_unsubscribe_message(unsubscribe_message, expose_recipients) email_text_context += unsubscribe_link.text email_content = get_formatted_html(subject, message, email_account=email_account, header=header, unsubscribe_link=unsubscribe_link) # add to queue add(recipients, sender, subject, formatted=email_content, text_content=email_text_context, reference_doctype=reference_doctype, reference_name=reference_name, attachments=attachments, reply_to=reply_to, cc=cc, bcc=bcc, message_id=message_id, in_reply_to=in_reply_to, send_after=send_after, send_priority=send_priority, email_account=email_account, communication=communication, add_unsubscribe_link=add_unsubscribe_link, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, expose_recipients=expose_recipients, read_receipt=read_receipt, queue_separately=queue_separately, is_notification = is_notification, inline_images = inline_images, header=header, now=now, print_letterhead=print_letterhead)
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=(), message_id=None, send_after=None): """Add email to sending queue (Bulk Email) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :param message: Email message. :param reference_doctype: Reference DocType of caller document. :param reference_name: Reference name of caller document. :param unsubscribe_method: URL method for unsubscribe. Default is `/api/method/frappe.email.bulk.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 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. """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.bulk.unsubscribe" if not recipients: return if isinstance(recipients, basestring): recipients = recipients.split(",") if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) if not sender or sender == "Administrator": email_account = get_outgoing_email_account() sender = email_account.get("sender") or email_account.email_id check_bulk_limit(recipients) formatted = get_formatted_html(subject, message) try: text_content = html2text(formatted) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"reference_doctype": reference_doctype, "reference_name": reference_name})] unsubscribed += [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"global_unsubscribe": 1})] else: unsubscribed = [] for email in filter(None, list(set(recipients))): if email not in unsubscribed: email_content = formatted email_text_context = text_content if reference_doctype: unsubscribe_url = get_unsubcribed_url(reference_doctype, reference_name, email, unsubscribe_method, unsubscribe_params) # add to queue email_content = add_unsubscribe_link(email_content, email, reference_doctype, reference_name, unsubscribe_url, unsubscribe_message) email_text_context += "\n" + _("This email was sent to {0}. To unsubscribe click on this link: {1}").format(email, unsubscribe_url) add(email, sender, subject, email_content, email_text_context, reference_doctype, reference_name, attachments, reply_to, cc, message_id, send_after)
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, 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): """Add email to sending queue (Email Queue) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :param message: Email message. :param text_content: Text version of email message. :param reference_doctype: Reference DocType of caller document. :param reference_name: Reference name of caller document. :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 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 Email Queue record :param now: Send immediately (don't send in the background) :param queue_separately: Queue each email separately :param is_notification: Marks email as notification so will not trigger notifications from system :param add_unsubscribe_link: Send unsubscribe link in the footer of the Email, default 1. :param inline_images: List of inline images as {"filename", "filecontent"}. All src properties will be replaced with random Content-Id :param header: Append header in email (boolean) """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe" if not recipients and not cc: return if isinstance(recipients, string_types): recipients = split_emails(recipients) if isinstance(cc, string_types): cc = split_emails(cc) if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) email_account = get_outgoing_email_account(True, append_to=reference_doctype, sender=sender) if not sender or sender == "Administrator": sender = email_account.default_sender check_email_limit(recipients) if not text_content: try: text_content = html2text(message) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [ d.email for d in frappe.db.get_all( "Email Unsubscribe", "email", { "reference_doctype": reference_doctype, "reference_name": reference_name }) ] unsubscribed += [ d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"global_unsubscribe": 1}) ] else: unsubscribed = [] recipients = [ r for r in list(set(recipients)) if r and r not in unsubscribed ] email_text_context = text_content should_append_unsubscribe = (add_unsubscribe_link and reference_doctype and (unsubscribe_message or reference_doctype == "Newsletter") and add_unsubscribe_link == 1) unsubscribe_link = None if should_append_unsubscribe: unsubscribe_link = get_unsubscribe_message(unsubscribe_message, expose_recipients) email_text_context += unsubscribe_link.text email_content = get_formatted_html(subject, message, email_account=email_account, header=header, unsubscribe_link=unsubscribe_link) # add to queue add(recipients, sender, subject, formatted=email_content, text_content=email_text_context, reference_doctype=reference_doctype, reference_name=reference_name, attachments=attachments, reply_to=reply_to, cc=cc, message_id=message_id, in_reply_to=in_reply_to, send_after=send_after, send_priority=send_priority, email_account=email_account, communication=communication, add_unsubscribe_link=add_unsubscribe_link, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, expose_recipients=expose_recipients, read_receipt=read_receipt, queue_separately=queue_separately, is_notification=is_notification, inline_images=inline_images, header=header, now=now)
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=[], message_id=None, in_reply_to=None, send_after=None, expose_recipients=None, send_priority=1, communication=None, now=False): """Add email to sending queue (Email Queue) :param recipients: List of recipients. :param sender: Email sender. :param subject: Email subject. :param message: Email message. :param reference_doctype: Reference DocType of caller document. :param reference_name: Reference name of caller document. :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 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 Email Queue record :param now: Send immediately (don't send in the background) """ if not unsubscribe_method: unsubscribe_method = "/api/method/frappe.email.queue.unsubscribe" if not recipients and not cc: return if isinstance(recipients, basestring): recipients = split_emails(recipients) if isinstance(send_after, int): send_after = add_days(nowdate(), send_after) email_account = get_outgoing_email_account(True, append_to=reference_doctype) if not sender or sender == "Administrator": sender = email_account.default_sender check_email_limit(recipients) formatted = get_formatted_html(subject, message, email_account=email_account) try: text_content = html2text(formatted) except HTMLParser.HTMLParseError: text_content = "See html attachment" if reference_doctype and reference_name: unsubscribed = [ d.email for d in frappe.db.get_all( "Email Unsubscribe", "email", { "reference_doctype": reference_doctype, "reference_name": reference_name }) ] unsubscribed += [ d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"global_unsubscribe": 1}) ] else: unsubscribed = [] recipients = [ r for r in list(set(recipients)) if r and r not in unsubscribed ] email_content = formatted email_text_context = text_content if reference_doctype and (unsubscribe_message or reference_doctype == "Newsletter"): unsubscribe_link = get_unsubscribe_message(unsubscribe_message, expose_recipients) email_content = email_content.replace("<!--unsubscribe link here-->", unsubscribe_link.html) email_text_context += unsubscribe_link.text # add to queue email_queue = add(recipients, sender, subject, email_content, email_text_context, reference_doctype, reference_name, attachments, reply_to, cc, message_id, in_reply_to, send_after, send_priority, email_account=email_account, communication=communication, unsubscribe_method=unsubscribe_method, unsubscribe_params=unsubscribe_params, expose_recipients=expose_recipients) if now: send_one(email_queue.name, now=True)