#!/usr/bin/env python3 """ SMTP webhook server """ import os import json import smtplib import sys import time from email.header import Header from email.mime.text import MIMEText import cherrypy import logging logging.basicConfig(stream=sys.stdout, format='%(name)s - %(levelname)s - %(message)s') class SMTPWebhookApp: """ SMTP webhook server """ def _send_mail(self): if not cherrypy.request.headers.get('Content-Length'): logging.error("error: Invalid content length.") return {"status": 400, "message": "Invalid content length."} cl = cherrypy.request.headers['Content-Length'] rawbody = cherrypy.request.body.read(int(cl)) req_body = json.loads(rawbody) if not req_body.get('subject') or req_body.get('subject') == '': logging.error("error: body field is required.") return {"status": 400, "message": "subject field is required."} if not req_body.get('body') or req_body.get('body') == '': logging.error("error: body field is required.") return {"status": 400, "message": "body field is required."} if not req_body.get('to_mail') or req_body.get('to_mail') == '': logging.error("error: to_mail field is required.") return {"status": 400, "message": "to_mail field is required."} subject = req_body['subject'] body = req_body['body'] to_mail = req_body['to_mail'] try: client = smtplib.SMTP(host=SMTP_SERVER_HOST, port=SMTP_SERVER_PORT) except (smtplib.SMTPConnectionError, TimeoutError) as e: time.sleep(0.2) logging.error("To: {}, error: {}".format(to_mail, e)) return {"status": 400, "message": "SMTP client error: {}.".format( e)} msg = MIMEText(body, 'plain', 'utf-8') msg['Subject'] = Header(subject, 'utf-8') msg['From'] = FROM_MAIL msg['To'] = to_mail try: client.ehlo() client.starttls() client.ehlo() client.login(msg["From"], FROM_MAIL_PASSWORD) client.sendmail(msg['From'], msg['To'], msg.as_string()) response = {"status": 200, "message": "mail sent successfully"} logging.info("To: {}, mail sent successfully".format(to_mail)) except smtplib.SMTPException as e: time.sleep(0.2) logging.error("To: {}, error: {}".format(to_mail, e)) response = {"status": 500, "message": "some error: {}".format(e)} finally: client.quit() return response @cherrypy.expose def send_mail(self): """ api endpoint for send mail """ data = self._send_mail() cherrypy.response.status = data["status"] cherrypy.response.headers["Content-Type"] = "application/json" return json.dumps(data["status"]).encode() ROOT = SMTPWebhookApp() SMTP_SERVER_PORT = 587 CHERRYPY_SERVER_HOST = "0.0.0.0" CHERRYPY_SERVER_PORT = 8081 if __name__ == "__main__": try: SMTP_SERVER_HOST = os.environ["SMTP_SERVER_HOST"] FROM_MAIL = os.environ["FROM_MAIL"] FROM_MAIL_PASSWORD = os.environ["FROM_MAIL_PASSWORD"] except KeyError: raise KeyError("Please check missing environment variables: " "SMTP_SERVER_HOST, FROM_MAIL, " "FROM_MAIL_PASSWORD") cherrypy.server.socket_host = CHERRYPY_SERVER_HOST cherrypy.server.socket_port = CHERRYPY_SERVER_PORT ENGINE = cherrypy.engine cherrypy.tree.mount(ROOT, config={}) if hasattr(ENGINE, "signal_handler"): ENGINE.signal_handler.subscribe() if hasattr(ENGINE, "console_control_handler"): ENGINE.console_control_handler.subscribe() try: ENGINE.start() except Exception: # pylint: disable=broad-except sys.exit(1) else: ENGINE.block()