refactored email libraries and added bulk email capability
This commit is contained in:
parent
8598d18cf8
commit
ef38508b3b
8 changed files with 397 additions and 186 deletions
0
py/core/doctype/bulk_email/__init__.py
Normal file
0
py/core/doctype/bulk_email/__init__.py
Normal file
103
py/core/doctype/bulk_email/bulk_email.txt
Normal file
103
py/core/doctype/bulk_email/bulk_email.txt
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# DocType, Bulk Email
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-08-02 15:17:28',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-08-02 15:17:29',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'description': u'Bulk Email records.',
|
||||
'doctype': 'DocType',
|
||||
'document_type': u'System',
|
||||
'in_create': 1,
|
||||
'module': u'Core',
|
||||
'name': '__common__',
|
||||
'read_only': 1,
|
||||
'version': 1
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Bulk Email',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Bulk Email',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1
|
||||
},
|
||||
|
||||
# DocType, Bulk Email
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Bulk Email'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'role': u'Administrator'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sender',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Sender'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'recipient',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Recipient'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'message',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Message'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'status',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Status'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'error',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Error'
|
||||
}
|
||||
]
|
||||
65
py/webnotes/tests/test_email.py
Normal file
65
py/webnotes/tests/test_email.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import os, sys
|
||||
|
||||
sys.path.append('.')
|
||||
sys.path.append('lib/py')
|
||||
sys.path.append('erpnext')
|
||||
|
||||
import unittest, webnotes
|
||||
|
||||
class TestEmail(unittest.TestCase):
|
||||
def setUp(self):
|
||||
webnotes.conn.begin()
|
||||
|
||||
def tearDown(self):
|
||||
webnotes.conn.rollback()
|
||||
|
||||
def test_send(self):
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
#sendmail('rmehta@gmail.com', subject='Test Mail', msg="Test Content")
|
||||
|
||||
def test_bulk(self):
|
||||
from webnotes.utils.email_lib.bulk import send
|
||||
send(recipients = ['rmehta@gmail.com', 'rushabh@erpnext.com'],
|
||||
doctype='Lead', email_field='email_id', first_name_field='lead_name',
|
||||
last_name_field=None, subject='Testing Bulk', message='This is a bulk mail!')
|
||||
|
||||
bulk = webnotes.conn.sql("""select * from `tabBulk Email` where status='Not Sent'""", as_dict=1)
|
||||
self.assertEquals(len(bulk), 2)
|
||||
self.assertTrue('rmehta@gmail.com' in [d['recipient'] for d in bulk])
|
||||
self.assertTrue('rushabh@erpnext.com' in [d['recipient'] for d in bulk])
|
||||
self.assertTrue('Unsubscribe' in bulk[0]['message'])
|
||||
|
||||
def test_flush(self):
|
||||
self.test_bulk()
|
||||
from webnotes.utils.email_lib.bulk import flush
|
||||
flush()
|
||||
bulk = webnotes.conn.sql("""select * from `tabBulk Email` where status='Sent'""", as_dict=1)
|
||||
self.assertEquals(len(bulk), 2)
|
||||
self.assertTrue('rmehta@gmail.com' in [d['recipient'] for d in bulk])
|
||||
self.assertTrue('rushabh@erpnext.com' in [d['recipient'] for d in bulk])
|
||||
webnotes.conn.sql("""delete from `tabBulk Email`""", auto_commit=True)
|
||||
|
||||
def test_unsubscribe(self):
|
||||
from webnotes.utils.email_lib.bulk import unsubscribe, send
|
||||
webnotes.form_dict = {
|
||||
'email':'rmehta@gmail.com',
|
||||
'type':'Lead',
|
||||
'email_field':'email_id'
|
||||
}
|
||||
unsubscribe()
|
||||
|
||||
send(recipients = ['rmehta@gmail.com', 'rushabh@erpnext.com'],
|
||||
doctype='Lead', email_field='email_id', first_name_field='lead_name',
|
||||
last_name_field=None, subject='Testing Bulk', message='This is a bulk mail!')
|
||||
|
||||
bulk = webnotes.conn.sql("""select * from `tabBulk Email` where status='Not Sent'""",
|
||||
as_dict=1)
|
||||
self.assertEquals(len(bulk), 1)
|
||||
self.assertFalse('rmehta@gmail.com' in [d['recipient'] for d in bulk])
|
||||
self.assertTrue('rushabh@erpnext.com' in [d['recipient'] for d in bulk])
|
||||
self.assertTrue('Unsubscribe' in bulk[0]['message'])
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
webnotes.connect()
|
||||
unittest.main()
|
||||
|
|
@ -66,21 +66,26 @@ def extract_email_id(s):
|
|||
return s
|
||||
|
||||
def validate_email_add(email_str):
|
||||
"""
|
||||
Validates the email string
|
||||
"""
|
||||
"""Validates the email string"""
|
||||
s = extract_email_id(email_str)
|
||||
import re
|
||||
#return re.match("^[a-zA-Z0-9._%-]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email_str)
|
||||
return re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", s)
|
||||
|
||||
def sendmail(recipients, sender='', msg='', subject='[No Subject]', parts=[], cc=[], attach=[]):
|
||||
"""
|
||||
Send an email. For more details see :func:`email_lib.sendmail`
|
||||
"""
|
||||
"""Send an email. For more details see :func:`email_lib.sendmail`"""
|
||||
import webnotes.utils.email_lib
|
||||
return email_lib.sendmail(recipients, sender, msg, subject, parts, cc, attach)
|
||||
|
||||
|
||||
def get_request_site_address():
|
||||
"""get app url from request"""
|
||||
import os
|
||||
try:
|
||||
return 'HTTPS' in os.environ.get('SERVER_PROTOCOL') and 'https://' or 'http://' \
|
||||
+ os.environ.get('HTTP_HOST')
|
||||
except TypeError, e:
|
||||
return 'http://localhost'
|
||||
|
||||
def generate_hash():
|
||||
"""
|
||||
Generates random hash for session id
|
||||
|
|
|
|||
|
|
@ -22,101 +22,25 @@
|
|||
|
||||
import webnotes
|
||||
|
||||
def sendmail_html(sender, recipients, subject, html, text=None, template=None, send_now=1, reply_to=None):
|
||||
"""
|
||||
Send an html mail with alternative text and using Page Templates
|
||||
"""
|
||||
sendmail(recipients, sender, html, subject,
|
||||
send_now = send_now, reply_to = reply_to, template = template)
|
||||
|
||||
def make_html_body(content, template = None):
|
||||
"""
|
||||
Generate html content from a Page Template object
|
||||
"""
|
||||
template_html = '<div class="margin: 12px">%(content)s</div>'
|
||||
|
||||
if template:
|
||||
from webnotes.model.code import get_code
|
||||
template_html = get_code(webnotes.conn.get_value('Page Template', template, 'module'), 'Page Template', template, 'html', fieldname='template')
|
||||
|
||||
return template_html % {'content': content}
|
||||
|
||||
def sendmail_md(recipients, sender=None, msg=None, subject=None, from_defs=0):
|
||||
def sendmail_md(recipients, sender=None, msg=None, subject=None):
|
||||
"""send markdown email"""
|
||||
import markdown2
|
||||
sendmail(recipients, sender, markdown2.markdown(msg), subject, txt=msg, from_defs=from_defs)
|
||||
|
||||
def sendmail(recipients, sender='', msg='', subject='[No Subject]', txt=None, \
|
||||
parts=[], cc=[], attach=[], send_now=1, reply_to=None, template=None, from_defs=0):
|
||||
"""
|
||||
send an html email as multipart with attachments and all
|
||||
"""
|
||||
|
||||
from webnotes.utils.email_lib.html2text import html2text
|
||||
from webnotes.utils.email_lib.send import EMail
|
||||
import HTMLParser
|
||||
|
||||
email = EMail(sender, recipients, subject, reply_to=reply_to, from_defs=from_defs)
|
||||
email.cc = cc
|
||||
|
||||
if msg:
|
||||
if template:
|
||||
msg = make_html_body(msg, template)
|
||||
else:
|
||||
# if not html, then lets put some whitespace
|
||||
if (not '<br>' in msg) and (not '<p>' in msg):
|
||||
msg = msg.replace('\n','<br>')
|
||||
|
||||
footer = get_footer()
|
||||
|
||||
# encode using utf-8
|
||||
footer = footer.encode('utf-8', 'ignore')
|
||||
|
||||
msg = msg + (footer or '')
|
||||
if txt:
|
||||
email.set_text(txt)
|
||||
else:
|
||||
try:
|
||||
msg_unicode = msg
|
||||
if isinstance(msg, str):
|
||||
msg_unicode = unicode(msg, 'utf-8', 'ignore')
|
||||
email.set_text(html2text(msg_unicode))
|
||||
except HTMLParser.HTMLParseError:
|
||||
pass
|
||||
email.set_html(msg)
|
||||
for p in parts:
|
||||
email.set_message(p[1])
|
||||
for a in attach:
|
||||
email.attach(a)
|
||||
|
||||
email.send(send_now)
|
||||
|
||||
|
||||
def get_footer():
|
||||
"""
|
||||
Returns combination of footer from globals and Control Panel
|
||||
"""
|
||||
|
||||
footer = webnotes.conn.get_value('Control Panel',None,'mail_footer') or ''
|
||||
footer += (webnotes.conn.get_global('global_mail_footer') or '')
|
||||
return footer
|
||||
sendmail(recipients, sender, markdown2.markdown(msg), subject)
|
||||
|
||||
def sendmail(recipients, sender='', msg='', subject='[No Subject]'):
|
||||
"""send an html email as multipart with attachments and all"""
|
||||
from webnotes.utils.email_lib.smtp import get_email
|
||||
get_email(recipients, sender, msg, subject).send()
|
||||
|
||||
@webnotes.whitelist()
|
||||
def send_form():
|
||||
"""
|
||||
Emails a print format (form)
|
||||
Called from form UI
|
||||
"""
|
||||
|
||||
"""Emails a print format (form). Called from form UI"""
|
||||
from webnotes.utils.email_lib.form_email import FormEmail
|
||||
FormEmail().send()
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_contact_list():
|
||||
"""
|
||||
Returns contacts (from autosuggest)
|
||||
"""
|
||||
|
||||
"""Returns contacts (from autosuggest)"""
|
||||
cond = ['`%s` like "%s%%"' % (f,
|
||||
webnotes.form.getvalue('txt')) for f in webnotes.form.getvalue('where').split(',')]
|
||||
cl = webnotes.conn.sql("select `%s` from `tab%s` where %s" % (
|
||||
|
|
@ -126,5 +50,3 @@ def get_contact_list():
|
|||
)
|
||||
)
|
||||
webnotes.response['cl'] = filter(None, [c[0] for c in cl])
|
||||
|
||||
|
||||
|
|
|
|||
118
py/webnotes/utils/email_lib/bulk.py
Normal file
118
py/webnotes/utils/email_lib/bulk.py
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
|
||||
#
|
||||
# MIT License (MIT)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
import webnotes
|
||||
|
||||
def send(recipients=[], doctype='Profile', email_field='email', first_name_field="first_name",
|
||||
last_name_field="last_name", subject='[No Subject]', message='[No Content]'):
|
||||
"""send bulk mail if not unsubscribed and within conf.bulk_mail_limit"""
|
||||
import webnotes
|
||||
def is_unsubscribed(rdata):
|
||||
if not rdata: return 1
|
||||
return rdata[0]['unsubscribed']
|
||||
|
||||
def check_bulk_limit(new_mails):
|
||||
import conf
|
||||
from webnotes.utils import nowdate
|
||||
todays_bulk = webnotes.conn.sql("""select count(*) from `tabBulk Email` where
|
||||
datediff(%s, creation)<1""" % nowdate())[0][0]
|
||||
|
||||
bulk_mail_limit = getattr(conf, 'bulk_mail_limit', 200)
|
||||
if todays_bulk + len(recipients) > bulk_mail_limit:
|
||||
webnotes.msgprint("""Buik Mail Limit Crossed""", raise_exception=1)
|
||||
|
||||
def add_unsubscribe_link(email):
|
||||
from webnotes.utils import get_request_site_address
|
||||
return message + """<div style="padding: 7px; border-top: 1px solid #aaa>">
|
||||
<small><a href="http://%s/server.py?cmd=%s&email=%s&type=%s&email_field=%s">
|
||||
Unsubscribe</a> from this list.</small></div>""" % (get_request_site_address(),
|
||||
'webnotes.utils.email_lib.bulk.unsubscribe', email, doctype, email_field)
|
||||
|
||||
def full_name(rdata):
|
||||
fname = rdata[0].get(first_name_field, '')
|
||||
lname = rdata[0].get(last_name_field, '')
|
||||
if fname and not lname:
|
||||
return fname
|
||||
elif lname and not fname:
|
||||
return lname
|
||||
elif fname and lname:
|
||||
return fname + ' ' + lname
|
||||
else:
|
||||
return rdata[0][email_field].split('@')[0].title()
|
||||
|
||||
check_bulk_limit(len(recipients))
|
||||
sender = webnotes.conn.get_value('Email Settings', None, 'auto_mail_id')
|
||||
|
||||
for r in recipients:
|
||||
rdata = webnotes.conn.sql("""select * from `tab%s` where %s=%s""" % (doctype,
|
||||
email_field, '%s'), r, as_dict=1)
|
||||
if not is_unsubscribed(rdata):
|
||||
# add to queue
|
||||
add(r, sender, subject, add_unsubscribe_link(r) % {"full_name":full_name(rdata)})
|
||||
|
||||
def add(email, sender, subject, message):
|
||||
"""add to bulk mail queue"""
|
||||
from webnotes.model.doc import Document
|
||||
from webnotes.utils.email_lib.smtp import get_email
|
||||
|
||||
e = Document('Bulk Email')
|
||||
e.sender = sender
|
||||
e.recipient = email
|
||||
e.message = get_email(email, sender=e.sender, msg=message, subject=subject).as_string()
|
||||
e.status = 'Not Sent'
|
||||
e.save()
|
||||
|
||||
@webnotes.whitelist(allow_guest=True)
|
||||
def unsubscribe():
|
||||
doctype = webnotes.form_dict.get('type')
|
||||
field = webnotes.form_dict.get('email_field')
|
||||
email = webnotes.form_dict.get('email')
|
||||
webnotes.conn.sql("""update `tab%s` set unsubscribed=1
|
||||
where email_id=%s""" % (doctype, '%s'), email)
|
||||
|
||||
webnotes.unsubscribed_email = email
|
||||
webnotes.response['type'] = 'page'
|
||||
webnotes.response['page_name'] = 'unsubscribed.html'
|
||||
|
||||
def flush():
|
||||
"""flush email queue, every time: called from scheduler"""
|
||||
import webnotes
|
||||
from webnotes.utils.email_lib.smtp import SMTPServer
|
||||
|
||||
smptserver = SMTPServer()
|
||||
|
||||
for email in webnotes.conn.sql("""select * from `tabBulk Email` where status='Not Sent'""",
|
||||
as_dict=1):
|
||||
webnotes.conn.sql("""update `tabBulk Email` set status='Sending' where name=%s""",
|
||||
email["name"], auto_commit=True)
|
||||
try:
|
||||
smptserver.sess.sendmail(email["sender"], email["recipient"], email["message"])
|
||||
webnotes.conn.sql("""update `tabBulk Email` set status='Sent' where name=%s""",
|
||||
email["name"], auto_commit=True)
|
||||
except Exception, e:
|
||||
webnotes.conn.sql("""update `tabBulk Email` set status='Error', error=%s
|
||||
where name=%s""", (str(e), email["name"]), auto_commit=True)
|
||||
|
||||
def clear_outbox():
|
||||
"""remove mails older than 7 days in Outbox"""
|
||||
webnotes.conn.sql("""delete from `tabBulk Email` where
|
||||
datediff(now(), creation) > 7""", (str(e), email["name"]), auto_commit=True)
|
||||
|
|
@ -26,7 +26,7 @@ from webnotes.utils import cint
|
|||
form = webnotes.form
|
||||
|
||||
from webnotes.utils.email_lib import get_footer
|
||||
from webnotes.utils.email_lib.send import EMail
|
||||
from webnotes.utils.email_lib.smtp import EMail
|
||||
|
||||
class FormEmail:
|
||||
"""
|
||||
|
|
@ -204,7 +204,7 @@ class FormEmail:
|
|||
if self.cc:
|
||||
self.email.cc = [self.cc]
|
||||
|
||||
self.email.send(send_now=1)
|
||||
self.email.send()
|
||||
self.make_communication()
|
||||
|
||||
webnotes.msgprint('Sent')
|
||||
|
|
|
|||
|
|
@ -30,13 +30,22 @@ import conf
|
|||
from webnotes import msgprint
|
||||
import email
|
||||
|
||||
def get_email(recipients, sender='', msg='', subject='[No Subject]'):
|
||||
"""send an html email as multipart with attachments and all"""
|
||||
email = EMail(sender, recipients, subject)
|
||||
if (not '<br>' in msg) and (not '<p>' in msg) and (not '<div' in msg):
|
||||
msg = msg.replace('\n', '<br>')
|
||||
email.set_html(msg)
|
||||
|
||||
return email
|
||||
|
||||
class EMail:
|
||||
"""
|
||||
Wrapper on the email module. Email object represents emails to be sent to the client.
|
||||
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='', from_defs=0, alternative=0, reply_to=None):
|
||||
def __init__(self, sender='', recipients=[], subject='', alternative=0, reply_to=None):
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email import Charset
|
||||
Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8')
|
||||
|
|
@ -48,7 +57,6 @@ class EMail:
|
|||
# remove null
|
||||
recipients = filter(None, recipients)
|
||||
|
||||
self.from_defs = from_defs
|
||||
self.sender = sender
|
||||
self.reply_to = reply_to or sender
|
||||
self.recipients = recipients
|
||||
|
|
@ -58,6 +66,7 @@ class EMail:
|
|||
self.msg_multipart = MIMEMultipart('alternative')
|
||||
self.msg_root.attach(self.msg_multipart)
|
||||
self.cc = []
|
||||
self.html_set = False
|
||||
|
||||
def set_text(self, message):
|
||||
"""
|
||||
|
|
@ -68,21 +77,32 @@ class EMail:
|
|||
message = message.encode('utf-8')
|
||||
part = MIMEText(message, 'plain', 'utf-8')
|
||||
self.msg_multipart.attach(part)
|
||||
|
||||
|
||||
def set_html(self, message):
|
||||
"""
|
||||
Attach message in the html portion of multipart/alternative
|
||||
"""
|
||||
from email.mime.text import MIMEText
|
||||
if isinstance(message, unicode):
|
||||
message = message.encode('utf-8')
|
||||
part = MIMEText(message, 'html', 'utf-8')
|
||||
"""Attach message in the html portion of multipart/alternative"""
|
||||
from email.mime.text import MIMEText
|
||||
message = unicode(message) + self.get_footer()
|
||||
|
||||
# this is the first html part of a multi-part message,
|
||||
# convert to text well
|
||||
if not self.html_set:
|
||||
self.set_html_text(message)
|
||||
|
||||
part = MIMEText(message.encode('utf-8'), 'html', 'utf-8')
|
||||
self.msg_multipart.attach(part)
|
||||
self.html_set = True
|
||||
|
||||
def set_html_text(self, html):
|
||||
"""return html2text"""
|
||||
import HTMLParser
|
||||
from webnotes.utils.email_lib.html2text import html2text
|
||||
try:
|
||||
self.set_text(html2text(html))
|
||||
except HTMLParser.HTMLParseError:
|
||||
pass
|
||||
|
||||
def set_message(self, message, mime_type='text/html', as_attachment=0, filename='attachment.html'):
|
||||
"""
|
||||
Append the message with MIME content to the root node (as attachment)
|
||||
"""
|
||||
"""Append the message with MIME content to the root node (as attachment)"""
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
maintype, subtype = mime_type.split('/')
|
||||
|
|
@ -92,11 +112,15 @@ class EMail:
|
|||
part.add_header('Content-Disposition', 'attachment', filename=filename)
|
||||
|
||||
self.msg_root.attach(part)
|
||||
|
||||
def get_footer(self):
|
||||
"""append a footer"""
|
||||
footer = webnotes.conn.get_value('Control Panel',None,'mail_footer') or ''
|
||||
footer += (webnotes.conn.get_global('global_mail_footer') or '')
|
||||
return unicode(footer)
|
||||
|
||||
def attach_file(self, n):
|
||||
"""
|
||||
attach a file from the `FileData` table
|
||||
"""
|
||||
"""attach a file from the `FileData` table"""
|
||||
from webnotes.utils.file_manager import get_file
|
||||
res = get_file(n)
|
||||
if not res:
|
||||
|
|
@ -105,7 +129,7 @@ class EMail:
|
|||
self.add_attachment(res[0], res[1])
|
||||
|
||||
def add_attachment(self, fname, fcontent, content_type=None):
|
||||
|
||||
"""add attachment"""
|
||||
from email.mime.audio import MIMEAudio
|
||||
from email.mime.base import MIMEBase
|
||||
from email.mime.image import MIMEImage
|
||||
|
|
@ -143,12 +167,10 @@ class EMail:
|
|||
self.msg_root.attach(part)
|
||||
|
||||
def validate(self):
|
||||
"""
|
||||
validate the email ids
|
||||
"""
|
||||
"""validate the email ids"""
|
||||
if not self.sender:
|
||||
self.sender = hasattr(conf, 'auto_email_id') \
|
||||
and conf.auto_email_id or '"ERPNext Notification" <automail@erpnext.com>'
|
||||
self.sender = webnotes.conn.get_value('Email Settings', None, 'auto_email_id') \
|
||||
or getattr(conf, 'auto_email_id', '"ERPNext Notification" <notification@erpnext.com>')
|
||||
|
||||
from webnotes.utils import validate_email_add
|
||||
# validate ids
|
||||
|
|
@ -162,31 +184,8 @@ class EMail:
|
|||
if not validate_email_add(e):
|
||||
webnotes.msgprint("%s is not a valid email id" % e, raise_exception = 1)
|
||||
|
||||
def setup(self):
|
||||
"""
|
||||
setup the SMTP (outgoing) server from `Control Panel` or defs.py
|
||||
"""
|
||||
if self.from_defs:
|
||||
import webnotes
|
||||
self.server = getattr(conf,'mail_server','')
|
||||
self.login = getattr(conf,'mail_login','')
|
||||
self.port = getattr(conf,'mail_port',None)
|
||||
self.password = getattr(conf,'mail_password','')
|
||||
self.use_ssl = getattr(conf,'use_ssl',0)
|
||||
|
||||
else:
|
||||
import webnotes.model.doc
|
||||
from webnotes.utils import cint
|
||||
|
||||
# get defaults from control panel
|
||||
es = webnotes.model.doc.Document('Email Settings','Email Settings')
|
||||
self.server = es.outgoing_mail_server.encode('utf-8') or getattr(conf,'mail_server','')
|
||||
self.login = es.mail_login.encode('utf-8') or getattr(conf,'mail_login','')
|
||||
self.port = cint(es.mail_port) or getattr(conf,'mail_port',None)
|
||||
self.password = es.mail_password.encode('utf-8') or getattr(conf,'mail_password','')
|
||||
self.use_ssl = cint(es.use_ssl) or cint(getattr(conf, 'use_ssl', ''))
|
||||
|
||||
def make_msg(self):
|
||||
def make(self):
|
||||
"""build into msg_root"""
|
||||
self.msg_root['Subject'] = self.subject
|
||||
self.msg_root['From'] = self.sender
|
||||
self.msg_root['To'] = ', '.join([r.strip() for r in self.recipients])
|
||||
|
|
@ -194,46 +193,43 @@ class EMail:
|
|||
self.msg_root['Reply-To'] = self.reply_to
|
||||
if self.cc:
|
||||
self.msg_root['CC'] = ', '.join([r.strip() for r in self.cc])
|
||||
|
||||
def add_to_queue(self):
|
||||
# write to a file called "email_queue" or as specified in email
|
||||
q = EmailQueue()
|
||||
q.push({
|
||||
'server': self.server,
|
||||
'port': self.port,
|
||||
'use_ssl': self.use_ssl,
|
||||
'login': self.login,
|
||||
'password': self.password,
|
||||
'sender': self.sender,
|
||||
'recipients': self.recipients,
|
||||
'msg': self.msg_root.as_string()
|
||||
})
|
||||
q.close()
|
||||
|
||||
def send(self, send_now = 0):
|
||||
"""
|
||||
send the message
|
||||
"""
|
||||
from webnotes.utils import cint
|
||||
|
||||
self.setup()
|
||||
def as_string(self):
|
||||
"""validate, build message and convert to string"""
|
||||
self.validate()
|
||||
self.make_msg()
|
||||
self.make()
|
||||
return self.msg_root.as_string()
|
||||
|
||||
sess = self.smtp_connect()
|
||||
def send(self, as_bulk=False):
|
||||
"""send the message or add it to Outbox Email"""
|
||||
SMTPServer().sess.sendmail(self.sender, self.recipients, self.as_string())
|
||||
|
||||
sess.sendmail(self.sender, self.recipients, self.msg_root.as_string())
|
||||
|
||||
class SMTPServer:
|
||||
def __init__(self, login=None, password=None, server=None, port=None, use_ssl=None):
|
||||
import webnotes.model.doc
|
||||
from webnotes.utils import cint
|
||||
|
||||
# get defaults from control panel
|
||||
es = webnotes.model.doc.Document('Email Settings','Email Settings')
|
||||
self.server = server or es.outgoing_mail_server.encode('utf-8') \
|
||||
or getattr(conf,'mail_server','')
|
||||
self.login = login or es.mail_login.encode('utf-8') \
|
||||
or getattr(conf,'mail_login','')
|
||||
self.port = port or cint(es.mail_port) \
|
||||
or getattr(conf,'mail_port',None)
|
||||
self.password = password or es.mail_password.encode('utf-8') \
|
||||
or getattr(conf,'mail_password','')
|
||||
self.use_ssl = use_ssl or cint(es.use_ssl) \
|
||||
or cint(getattr(conf, 'use_ssl', ''))
|
||||
self._sess = None
|
||||
|
||||
@property
|
||||
def sess(self):
|
||||
"""get session"""
|
||||
if self._sess:
|
||||
return self._sess
|
||||
|
||||
try:
|
||||
sess.quit()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def smtp_connect(self):
|
||||
"""
|
||||
Gets a smtp connection and handles errors
|
||||
"""
|
||||
from webnotes.utils import cint
|
||||
import smtplib
|
||||
import _socket
|
||||
|
|
@ -245,26 +241,26 @@ class EMail:
|
|||
raise webnotes.OutgoingEmailError, err_msg
|
||||
|
||||
try:
|
||||
sess = smtplib.SMTP(self.server, cint(self.port) or None)
|
||||
self._sess = smtplib.SMTP(self.server, cint(self.port) or None)
|
||||
|
||||
if not sess:
|
||||
if not self._sess:
|
||||
err_msg = 'Could not connect to outgoing email server'
|
||||
webnotes.msgprint(err_msg)
|
||||
raise webnotes.OutgoingEmailError, err_msg
|
||||
|
||||
if self.use_ssl:
|
||||
sess.ehlo()
|
||||
sess.starttls()
|
||||
sess.ehlo()
|
||||
self._sess.ehlo()
|
||||
self._sess.starttls()
|
||||
self._sess.ehlo()
|
||||
|
||||
ret = sess.login(self.login, self.password)
|
||||
ret = self._sess.login(self.login, self.password)
|
||||
|
||||
# check if logged correctly
|
||||
if ret[0]!=235:
|
||||
msgprint(ret[1])
|
||||
raise webnotes.OutgoingEmailError, ret[1]
|
||||
|
||||
return sess
|
||||
return self._sess
|
||||
|
||||
except _socket.error, e:
|
||||
# Invalid mail server -- due to refusing connection
|
||||
|
|
@ -276,4 +272,6 @@ class EMail:
|
|||
except smtplib.SMTPException, e:
|
||||
webnotes.msgprint('There is something wrong with your Outgoing Mail Settings. \
|
||||
Please contact us at support@erpnext.com')
|
||||
raise webnotes.OutgoingEmailError, e
|
||||
raise webnotes.OutgoingEmailError, e
|
||||
|
||||
|
||||
Loading…
Add table
Reference in a new issue