diff --git a/homeassistant/components/notify/smtp.py b/homeassistant/components/notify/smtp.py index 7664753f2ee..27c74571d40 100644 --- a/homeassistant/components/notify/smtp.py +++ b/homeassistant/components/notify/smtp.py @@ -6,14 +6,18 @@ https://home-assistant.io/components/notify.smtp/ """ import logging import smtplib +from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText +from email.mime.image import MIMEImage from homeassistant.components.notify import ( - ATTR_TITLE, DOMAIN, BaseNotificationService) + ATTR_TITLE, ATTR_DATA, DOMAIN, BaseNotificationService) from homeassistant.helpers import validate_config _LOGGER = logging.getLogger(__name__) +ATTR_IMAGES = 'images' # optional embedded image file attachments + def get_service(hass, config): """Get the mail notification service.""" @@ -22,52 +26,21 @@ def get_service(hass, config): _LOGGER): return None - smtp_server = config.get('server', 'localhost') - port = int(config.get('port', '25')) - username = config.get('username', None) - password = config.get('password', None) - starttls = int(config.get('starttls', 0)) - debug = config.get('debug', 0) - - server = None - try: - server = smtplib.SMTP(smtp_server, port, timeout=5) - server.set_debuglevel(debug) - server.ehlo() - if starttls == 1: - server.starttls() - server.ehlo() - if username and password: - try: - server.login(username, password) - - except (smtplib.SMTPException, smtplib.SMTPSenderRefused): - _LOGGER.exception("Please check your settings.") - return None - - except smtplib.socket.gaierror: - _LOGGER.exception( - "SMTP server not found (%s:%s). " - "Please check the IP address or hostname of your SMTP server.", - smtp_server, port) + mail_service = MailNotificationService( + config.get('server', 'localhost'), + int(config.get('port', '25')), + config.get('sender', None), + int(config.get('starttls', 0)), + config.get('username', None), + config.get('password', None), + config.get('recipient', None), + config.get('debug', 0)) + if mail_service.connection_is_valid(): + return mail_service + else: return None - except smtplib.SMTPAuthenticationError: - _LOGGER.exception( - "Login not possible. " - "Please check your setting and/or your credentials.") - - return None - - finally: - if server: - server.quit() - - return MailNotificationService( - smtp_server, port, config['sender'], starttls, username, password, - config['recipient'], debug) - # pylint: disable=too-few-public-methods, too-many-instance-attributes class MailNotificationService(BaseNotificationService): @@ -99,17 +72,57 @@ class MailNotificationService(BaseNotificationService): mail.login(self.username, self.password) return mail - def send_message(self, message="", **kwargs): - """Send a message to a user.""" - mail = self.connect() - subject = kwargs.get(ATTR_TITLE) + def connection_is_valid(self): + """Check for valid config, verify connectivity.""" + server = None + try: + server = self.connect() + except smtplib.socket.gaierror: + _LOGGER.exception( + "SMTP server not found (%s:%s). " + "Please check the IP address or hostname of your SMTP server.", + self._server, self._port) + + return False + + except (smtplib.SMTPAuthenticationError, ConnectionRefusedError): + _LOGGER.exception( + "Login not possible. " + "Please check your setting and/or your credentials.") + + return False + + finally: + if server: + server.quit() + + return True + + def send_message(self, message="", **kwargs): + """ + Build and send a message to a user. + + Will send plain text normally, or will build a multipart HTML message + with inline image attachments if images config is defined. + """ + subject = kwargs.get(ATTR_TITLE) + data = kwargs.get(ATTR_DATA) + + if data: + msg = _build_multipart_msg(message, images=data.get(ATTR_IMAGES)) + else: + msg = _build_text_msg(message) - msg = MIMEText(message) msg['Subject'] = subject msg['To'] = self.recipient msg['From'] = self._sender msg['X-Mailer'] = 'HomeAssistant' + return self._send_email(msg) + + def _send_email(self, msg): + """Send the message.""" + mail = self.connect() for _ in range(self.tries): try: mail.sendmail(self._sender, self.recipient, @@ -122,3 +135,36 @@ class MailNotificationService(BaseNotificationService): mail = self.connect() mail.quit() + + +def _build_text_msg(message): + """Build plaintext email.""" + _LOGGER.debug('Building plain text email.') + return MIMEText(message) + + +def _build_multipart_msg(message, images): + """Build Multipart message with in-line images.""" + _LOGGER.debug('Building multipart email with embedded attachment(s).') + msg = MIMEMultipart('related') + msg_alt = MIMEMultipart('alternative') + msg.attach(msg_alt) + body_txt = MIMEText(message) + msg_alt.attach(body_txt) + body_text = ['
{}