diff --git a/pymodmilter/__init__.py b/pymodmilter/__init__.py index 725d291..050690e 100644 --- a/pymodmilter/__init__.py +++ b/pymodmilter/__init__.py @@ -16,9 +16,11 @@ __all__ = [ "actions", "base", "conditions", + "mailer", "modifications", "rules", "run", + "storages", "ModifyMilterConfig", "ModifyMilter"] diff --git a/pymodmilter/mailer.py b/pymodmilter/mailer.py new file mode 100644 index 0000000..51a913c --- /dev/null +++ b/pymodmilter/mailer.py @@ -0,0 +1,86 @@ +# PyMod-Milter is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# PyMod-Milter is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with PyMod-Milter. If not, see . +# + +import logging +import smtplib + +from multiprocessing import Process, Queue + + +logger = logging.getLogger(__name__) +queue = Queue(maxsize=50) +process = None + + +def smtp_send(smtp_host, smtp_port, mailfrom, recipient, mail): + s = smtplib.SMTP(host=smtp_host, port=smtp_port) + s.ehlo() + if s.has_extn("STARTTLS"): + s.starttls() + s.ehlo() + s.sendmail(mailfrom, [recipient], mail) + s.quit() + + +def mailprocess(): + "Mailer process to send emails asynchronously." + global logger + global queue + + try: + while True: + m = queue.get() + if not m: + break + + smtp_host, smtp_port, qid, mailfrom, recipient, mail, emailtype = m + try: + smtp_send(smtp_host, smtp_port, mailfrom, recipient, mail) + except Exception as e: + logger.error( + f"{qid}: error while sending {emailtype} " + f"to '{recipient}': {e}") + else: + logger.info( + f"{qid}: successfully sent {emailtype} to: {recipient}") + except KeyboardInterrupt: + pass + logger.debug("mailer process terminated") + + +def sendmail(smtp_host, smtp_port, qid, mailfrom, recipients, mail, + emailtype="email"): + "Send an email." + global logger + global process + global queue + + if isinstance(recipients, str): + recipients = [recipients] + + # start mailprocess if it is not started yet + if process is None: + process = Process(target=mailprocess) + process.daemon = True + logger.debug("starting mailer process") + process.start() + + for recipient in recipients: + try: + queue.put( + (smtp_host, smtp_port, qid, mailfrom, recipient, mail, + emailtype), + timeout=30) + except Queue.Full: + raise RuntimeError("email queue is full") diff --git a/pymodmilter/run.py b/pymodmilter/run.py index 5998a50..00baf6e 100644 --- a/pymodmilter/run.py +++ b/pymodmilter/run.py @@ -20,9 +20,8 @@ import logging import logging.handlers import sys -from pymodmilter import ModifyMilter +from pymodmilter import ModifyMilterConfig, ModifyMilter from pymodmilter import __version__ as version -from pymodmilter import ModifyMilterConfig def main():