From ef38508b3b3e50627135d9f32cee9b66c4e1bbf0 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 2 Aug 2012 18:02:38 +0530 Subject: [PATCH] refactored email libraries and added bulk email capability --- py/core/doctype/bulk_email/__init__.py | 0 py/core/doctype/bulk_email/bulk_email.txt | 103 ++++++++++ py/webnotes/tests/test_email.py | 65 +++++++ py/webnotes/utils/__init__.py | 19 +- py/webnotes/utils/email_lib/__init__.py | 96 +--------- py/webnotes/utils/email_lib/bulk.py | 118 ++++++++++++ py/webnotes/utils/email_lib/form_email.py | 4 +- .../utils/email_lib/{send.py => smtp.py} | 178 +++++++++--------- 8 files changed, 397 insertions(+), 186 deletions(-) create mode 100644 py/core/doctype/bulk_email/__init__.py create mode 100644 py/core/doctype/bulk_email/bulk_email.txt create mode 100644 py/webnotes/tests/test_email.py create mode 100644 py/webnotes/utils/email_lib/bulk.py rename py/webnotes/utils/email_lib/{send.py => smtp.py} (67%) diff --git a/py/core/doctype/bulk_email/__init__.py b/py/core/doctype/bulk_email/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/py/core/doctype/bulk_email/bulk_email.txt b/py/core/doctype/bulk_email/bulk_email.txt new file mode 100644 index 0000000000..09ff565cc6 --- /dev/null +++ b/py/core/doctype/bulk_email/bulk_email.txt @@ -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' + } +] \ No newline at end of file diff --git a/py/webnotes/tests/test_email.py b/py/webnotes/tests/test_email.py new file mode 100644 index 0000000000..a76d6a3354 --- /dev/null +++ b/py/webnotes/tests/test_email.py @@ -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() \ No newline at end of file diff --git a/py/webnotes/utils/__init__.py b/py/webnotes/utils/__init__.py index eccc8da8fb..812a116bd9 100644 --- a/py/webnotes/utils/__init__.py +++ b/py/webnotes/utils/__init__.py @@ -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 diff --git a/py/webnotes/utils/email_lib/__init__.py b/py/webnotes/utils/email_lib/__init__.py index 58ea04bcf7..c1b6b6af95 100644 --- a/py/webnotes/utils/email_lib/__init__.py +++ b/py/webnotes/utils/email_lib/__init__.py @@ -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 = '
%(content)s
' - - 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 '
' in msg) and (not '

' in msg): - msg = msg.replace('\n','
') - - 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]) - - diff --git a/py/webnotes/utils/email_lib/bulk.py b/py/webnotes/utils/email_lib/bulk.py new file mode 100644 index 0000000000..31a1cee4ee --- /dev/null +++ b/py/webnotes/utils/email_lib/bulk.py @@ -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 + """

+ + Unsubscribe from this list.
""" % (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) \ No newline at end of file diff --git a/py/webnotes/utils/email_lib/form_email.py b/py/webnotes/utils/email_lib/form_email.py index dc9bfabb6e..7bc63cbcb8 100644 --- a/py/webnotes/utils/email_lib/form_email.py +++ b/py/webnotes/utils/email_lib/form_email.py @@ -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') diff --git a/py/webnotes/utils/email_lib/send.py b/py/webnotes/utils/email_lib/smtp.py similarity index 67% rename from py/webnotes/utils/email_lib/send.py rename to py/webnotes/utils/email_lib/smtp.py index 7b02683182..e5ac54dede 100644 --- a/py/webnotes/utils/email_lib/send.py +++ b/py/webnotes/utils/email_lib/smtp.py @@ -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 '
' in msg) and (not '

' in msg) and (not '') + 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" ' + self.sender = webnotes.conn.get_value('Email Settings', None, 'auto_email_id') \ + or getattr(conf, 'auto_email_id', '"ERPNext Notification" ') 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 \ No newline at end of file + raise webnotes.OutgoingEmailError, e + + \ No newline at end of file