email: make EmailClient compatible with mylib.mylib.Config
This commit is contained in:
parent
ba4e85be50
commit
fdf68a8ee2
1 changed files with 108 additions and 53 deletions
161
mylib/email.py
161
mylib/email.py
|
@ -13,58 +13,98 @@ from email.encoders import encode_base64
|
||||||
|
|
||||||
from mako.template import Template as MakoTemplate
|
from mako.template import Template as MakoTemplate
|
||||||
|
|
||||||
|
from mylib.config import ConfigurableObject
|
||||||
|
from mylib.config import BooleanOption
|
||||||
|
from mylib.config import IntegerOption
|
||||||
|
from mylib.config import PasswordOption
|
||||||
|
from mylib.config import StringOption
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class EmailClient(object): # pylint: disable=useless-object-inheritance,too-many-instance-attributes
|
class EmailClient(ConfigurableObject): # pylint: disable=useless-object-inheritance,too-many-instance-attributes
|
||||||
"""
|
"""
|
||||||
Email client
|
Email client
|
||||||
|
|
||||||
This class abstract all interactions with the SMTP server.
|
This class abstract all interactions with the SMTP server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
smtp_host = None
|
_config_name = 'email'
|
||||||
smtp_port = None
|
_config_comment = 'Email'
|
||||||
smtp_ssl = None
|
_defaults = {
|
||||||
smtp_tls = None
|
'smtp_host': 'localhost',
|
||||||
smtp_user = None
|
'smtp_port': 25,
|
||||||
smtp_password = None
|
'smtp_ssl': False,
|
||||||
smtp_debug = None
|
'smtp_tls': False,
|
||||||
|
'smtp_user': None,
|
||||||
sender_name = None
|
'smtp_password': None,
|
||||||
sender_email = None
|
'smtp_debug': False,
|
||||||
|
'sender_name': 'No reply',
|
||||||
catch_all_addr = False
|
'sender_email': 'noreply@localhost',
|
||||||
just_try = False
|
'encoding': 'utf-8',
|
||||||
|
'catch_all_addr': None,
|
||||||
encoding = 'utf-8'
|
'just_try': False,
|
||||||
|
}
|
||||||
|
|
||||||
templates = dict()
|
templates = dict()
|
||||||
|
|
||||||
def __init__(self, smtp_host=None, smtp_port=None, smtp_ssl=None, smtp_tls=None, smtp_user=None, smtp_password=None, smtp_debug=None,
|
def __init__(self, templates=None, **kwargs):
|
||||||
sender_name=None, sender_email=None, catch_all_addr=None, just_try=None, encoding=None, templates=None):
|
super().__init__(**kwargs)
|
||||||
self.smtp_host = smtp_host if smtp_host else 'localhost'
|
|
||||||
self.smtp_port = smtp_port if smtp_port else 25
|
|
||||||
self.smtp_ssl = bool(smtp_ssl)
|
|
||||||
self.smtp_tls = bool(smtp_tls)
|
|
||||||
self.smtp_user = smtp_user if smtp_user else None
|
|
||||||
self.smtp_password = smtp_password if smtp_password else None
|
|
||||||
self.smtp_debug = bool(smtp_debug)
|
|
||||||
|
|
||||||
self.sender_name = sender_name if sender_name else "No reply"
|
|
||||||
self.sender_email = sender_email if sender_email else "noreply@localhost"
|
|
||||||
self.catch_all_addr = catch_all_addr if catch_all_addr else False
|
|
||||||
self.just_try = just_try if just_try else False
|
|
||||||
|
|
||||||
assert templates is None or isinstance(templates, dict)
|
assert templates is None or isinstance(templates, dict)
|
||||||
self.templates = templates if templates else dict()
|
self.templates = templates if templates else dict()
|
||||||
|
|
||||||
if encoding:
|
def configure(self, use_smtp=True, just_try=True, ** kwargs): # pylint: disable=arguments-differ
|
||||||
self.encoding = encoding
|
""" Configure options on registered mylib.Config object """
|
||||||
|
section = super().configure(**kwargs)
|
||||||
|
|
||||||
def forge_message(self, rcpt_to, subject=None, html_body=None, text_body=None, attachment_files=None,
|
if use_smtp:
|
||||||
attachment_payloads=None, sender_name=None, sender_email=None, encoding=None,
|
section.add_option(
|
||||||
template=None, **template_vars): # pylint: disable=too-many-arguments,too-many-locals
|
StringOption, 'smtp_host', default=self._defaults['smtp_host'],
|
||||||
|
comment='SMTP server hostname/IP address')
|
||||||
|
section.add_option(
|
||||||
|
IntegerOption, 'smtp_port', default=self._defaults['smtp_port'],
|
||||||
|
comment='SMTP server port')
|
||||||
|
section.add_option(
|
||||||
|
BooleanOption, 'smtp_ssl', default=self._defaults['smtp_ssl'],
|
||||||
|
comment='Use SSL on SMTP server connection')
|
||||||
|
section.add_option(
|
||||||
|
BooleanOption, 'smtp_tls', default=self._defaults['smtp_tls'],
|
||||||
|
comment='Use TLS on SMTP server connection')
|
||||||
|
section.add_option(
|
||||||
|
StringOption, 'smtp_user', default=self._defaults['smtp_user'],
|
||||||
|
comment='SMTP authentication username')
|
||||||
|
section.add_option(
|
||||||
|
PasswordOption, 'smtp_password', default=self._defaults['smtp_password'],
|
||||||
|
comment='SMTP authentication password (set to "keyring" to use XDG keyring)',
|
||||||
|
username_option='smtp_user', keyring_value='keyring')
|
||||||
|
section.add_option(
|
||||||
|
BooleanOption, 'smtp_debug', default=self._defaults['smtp_debug'],
|
||||||
|
comment='Enable SMTP debugging')
|
||||||
|
|
||||||
|
section.add_option(
|
||||||
|
StringOption, 'sender_name', default=self._defaults['sender_name'],
|
||||||
|
comment='Sender name')
|
||||||
|
section.add_option(
|
||||||
|
StringOption, 'sender_email', default=self._defaults['sender_email'],
|
||||||
|
comment='Sender email address')
|
||||||
|
section.add_option(
|
||||||
|
StringOption, 'encoding', default=self._defaults['encoding'],
|
||||||
|
comment='Email encoding')
|
||||||
|
section.add_option(
|
||||||
|
StringOption, 'catch_all_addr', default=self._defaults['catch_all_addr'],
|
||||||
|
comment='Catch all sent emails to this specified email address')
|
||||||
|
|
||||||
|
if just_try:
|
||||||
|
section.add_option(
|
||||||
|
BooleanOption, 'just_try', default=self._defaults['just_try'],
|
||||||
|
comment='Just-try mode: do not really send emails')
|
||||||
|
|
||||||
|
return section
|
||||||
|
|
||||||
|
def forge_message(self, rcpt_to, subject=None, html_body=None, text_body=None, # pylint: disable=too-many-arguments,too-many-locals
|
||||||
|
attachment_files=None, attachment_payloads=None, sender_name=None,
|
||||||
|
sender_email=None, encoding=None, template=None, **template_vars):
|
||||||
"""
|
"""
|
||||||
Forge a message
|
Forge a message
|
||||||
|
|
||||||
|
@ -83,11 +123,16 @@ class EmailClient(object): # pylint: disable=useless-object-inheritance,too-man
|
||||||
"""
|
"""
|
||||||
msg = MIMEMultipart('alternative')
|
msg = MIMEMultipart('alternative')
|
||||||
msg['To'] = email.utils.formataddr(rcpt_to) if isinstance(rcpt_to, tuple) else rcpt_to
|
msg['To'] = email.utils.formataddr(rcpt_to) if isinstance(rcpt_to, tuple) else rcpt_to
|
||||||
msg['From'] = email.utils.formataddr((sender_name or self.sender_name, sender_email or self.sender_email))
|
msg['From'] = email.utils.formataddr(
|
||||||
|
(
|
||||||
|
sender_name or self._get_option('sender_name'),
|
||||||
|
sender_email or self._get_option('sender_email')
|
||||||
|
)
|
||||||
|
)
|
||||||
if subject:
|
if subject:
|
||||||
msg['Subject'] = subject.format(**template_vars)
|
msg['Subject'] = subject.format(**template_vars)
|
||||||
msg['Date'] = email.utils.formatdate(None, True)
|
msg['Date'] = email.utils.formatdate(None, True)
|
||||||
encoding = encoding if encoding else self.encoding
|
encoding = encoding if encoding else self._get_option('encoding')
|
||||||
if template:
|
if template:
|
||||||
assert template in self.templates, "Unknwon template %s" % template
|
assert template in self.templates, "Unknwon template %s" % template
|
||||||
# Handle subject from template
|
# Handle subject from template
|
||||||
|
@ -149,44 +194,54 @@ class EmailClient(object): # pylint: disable=useless-object-inheritance,too-man
|
||||||
"""
|
"""
|
||||||
msg = msg if msg else self.forge_message(rcpt_to, subject, **forge_args)
|
msg = msg if msg else self.forge_message(rcpt_to, subject, **forge_args)
|
||||||
|
|
||||||
if just_try or self.just_try:
|
if just_try or self._get_option('just_try'):
|
||||||
log.debug('Just-try mode: do not really send this email to %s (subject="%s")', rcpt_to, subject or msg.get('subject', 'No subject'))
|
log.debug('Just-try mode: do not really send this email to %s (subject="%s")', rcpt_to, subject or msg.get('subject', 'No subject'))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.catch_all_addr:
|
catch_addr = self._get_option('catch_all_addr')
|
||||||
catch_addr = self.catch_all_addr
|
if catch_addr:
|
||||||
log.debug('Catch email originaly send to %s to %s', rcpt_to, catch_addr)
|
log.debug('Catch email originaly send to %s to %s', rcpt_to, catch_addr)
|
||||||
rcpt_to = catch_addr
|
rcpt_to = catch_addr
|
||||||
|
|
||||||
|
smtp_host = self._get_option('smtp_host')
|
||||||
|
smtp_port = self._get_option('smtp_port')
|
||||||
try:
|
try:
|
||||||
if self.smtp_ssl:
|
if self._get_option('smtp_ssl'):
|
||||||
logging.info("Establish SSL connection to server %s:%s", self.smtp_host, self.smtp_port)
|
logging.info("Establish SSL connection to server %s:%s", smtp_host, smtp_port)
|
||||||
server = smtplib.SMTP_SSL(self.smtp_host, self.smtp_port)
|
server = smtplib.SMTP_SSL(smtp_host, smtp_port)
|
||||||
else:
|
else:
|
||||||
logging.info("Establish connection to server %s:%s", self.smtp_host, self.smtp_port)
|
logging.info("Establish connection to server %s:%s", smtp_host, smtp_port)
|
||||||
server = smtplib.SMTP(self.smtp_host, self.smtp_port)
|
server = smtplib.SMTP(smtp_host, smtp_port)
|
||||||
if self.smtp_tls:
|
if self._get_option('smtp_tls'):
|
||||||
logging.info('Start TLS on SMTP connection')
|
logging.info('Start TLS on SMTP connection')
|
||||||
server.starttls()
|
server.starttls()
|
||||||
except smtplib.SMTPException:
|
except smtplib.SMTPException:
|
||||||
log.error('Error connecting to SMTP server %s:%s', self.smtp_host, self.smtp_port, exc_info=True)
|
log.error('Error connecting to SMTP server %s:%s', smtp_host, smtp_port, exc_info=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.smtp_debug:
|
if self._get_option('smtp_debug'):
|
||||||
server.set_debuglevel(True)
|
server.set_debuglevel(True)
|
||||||
|
|
||||||
if self.smtp_user and self.smtp_password:
|
smtp_user = self._get_option('smtp_user')
|
||||||
|
smtp_password = self._get_option('smtp_password')
|
||||||
|
if smtp_user and smtp_password:
|
||||||
try:
|
try:
|
||||||
log.info('Try to authenticate on SMTP connection as %s', self.smtp_user)
|
log.info('Try to authenticate on SMTP connection as %s', smtp_user)
|
||||||
server.login(self.smtp_user, self.smtp_password)
|
server.login(smtp_user, smtp_password)
|
||||||
except smtplib.SMTPException:
|
except smtplib.SMTPException:
|
||||||
log.error('Error authenticating on SMTP server %s:%s with user %s', self.smtp_host, self.smtp_port, self.smtp_user, exc_info=True)
|
log.error(
|
||||||
|
'Error authenticating on SMTP server %s:%s with user %s',
|
||||||
|
smtp_host, smtp_port, smtp_user, exc_info=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
error = False
|
error = False
|
||||||
try:
|
try:
|
||||||
log.info('Sending email to %s', rcpt_to)
|
log.info('Sending email to %s', rcpt_to)
|
||||||
server.sendmail(self.sender_email, [rcpt_to[1] if isinstance(rcpt_to, tuple) else rcpt_to], msg.as_string())
|
server.sendmail(
|
||||||
|
self._get_option('sender_email'),
|
||||||
|
[rcpt_to[1] if isinstance(rcpt_to, tuple) else rcpt_to],
|
||||||
|
msg.as_string()
|
||||||
|
)
|
||||||
except smtplib.SMTPException:
|
except smtplib.SMTPException:
|
||||||
error = True
|
error = True
|
||||||
log.error('Error sending email to %s', rcpt_to, exc_info=True)
|
log.error('Error sending email to %s', rcpt_to, exc_info=True)
|
||||||
|
|
Loading…
Reference in a new issue