diff --git a/pymodmilter/__init__.py b/pymodmilter/__init__.py index 050690e..86ad245 100644 --- a/pymodmilter/__init__.py +++ b/pymodmilter/__init__.py @@ -13,14 +13,15 @@ # __all__ = [ - "actions", + "action", "base", "conditions", "mailer", - "modifications", - "rules", + "modify", + "notify", + "rule", "run", - "storages", + "storage", "ModifyMilterConfig", "ModifyMilter"] @@ -45,7 +46,7 @@ from netaddr import IPNetwork, AddrFormatError from pymodmilter.base import CustomLogger, BaseConfig, MilterMessage from pymodmilter.base import replace_illegal_chars -from pymodmilter.rules import RuleConfig, Rule +from pymodmilter.rule import RuleConfig, Rule class ModifyMilterConfig(BaseConfig): @@ -339,12 +340,14 @@ class ModifyMilter(Milter.Base): self.msginfo = { "mailfrom": self.mailfrom, "rcpts": self.rcpts, - "storage_id": None} + "vars": {}} self._replacebody = False milter_action = None for rule in self.rules: milter_action = rule.execute(self) + self.logger.debug( + f"current template variables: {self.msginfo['vars']}") if milter_action is not None: break diff --git a/pymodmilter/actions.py b/pymodmilter/action.py similarity index 95% rename from pymodmilter/actions.py rename to pymodmilter/action.py index b082876..c295053 100644 --- a/pymodmilter/actions.py +++ b/pymodmilter/action.py @@ -23,7 +23,7 @@ from bs4 import BeautifulSoup from pymodmilter import CustomLogger, BaseConfig from pymodmilter.conditions import ConditionsConfig, Conditions -from pymodmilter import modifications, storages +from pymodmilter import modify, storage class ActionConfig(BaseConfig): @@ -58,7 +58,7 @@ class ActionConfig(BaseConfig): self["type"] = cfg["type"] if self["type"] == "add_header": - self["class"] = modifications.AddHeader + self["class"] = modify.AddHeader self["headersonly"] = True if "field" not in cfg and "header" in cfg: @@ -67,7 +67,7 @@ class ActionConfig(BaseConfig): self.add_string_arg(cfg, ("field", "value")) elif self["type"] == "mod_header": - self["class"] = modifications.ModHeader + self["class"] = modify.ModHeader self["headersonly"] = True if "field" not in cfg and "header" in cfg: @@ -88,7 +88,7 @@ class ActionConfig(BaseConfig): raise ValueError(f"{self['name']}: {arg}: {e}") elif self["type"] == "del_header": - self["class"] = modifications.DelHeader + self["class"] = modify.DelHeader self["headersonly"] = True if "field" not in cfg and "header" in cfg: @@ -108,7 +108,7 @@ class ActionConfig(BaseConfig): raise ValueError(f"{self['name']}: {arg}: {e}") elif self["type"] == "add_disclaimer": - self["class"] = modifications.AddDisclaimer + self["class"] = modify.AddDisclaimer self["headersonly"] = False if "html_template" not in cfg and "html_file" in cfg: @@ -149,7 +149,7 @@ class ActionConfig(BaseConfig): f"{self['name']}: unable to open/read template file: {e}") elif self["type"] == "rewrite_links": - self["class"] = modifications.RewriteLinks + self["class"] = modify.RewriteLinks self["headersonly"] = False self.add_string_arg(cfg, "repl") @@ -167,7 +167,7 @@ class ActionConfig(BaseConfig): self.add_bool_arg(cfg, "original") if self["storage_type"] == "file": - self["class"] = storages.FileMailStorage + self["class"] = storage.FileMailStorage self.add_string_arg(cfg, "directory") # check if directory exists and is writable if not os.path.isdir(self["args"]["directory"]) or \ diff --git a/pymodmilter/modifications.py b/pymodmilter/modify.py similarity index 100% rename from pymodmilter/modifications.py rename to pymodmilter/modify.py diff --git a/pymodmilter/notifications.py b/pymodmilter/notify.py similarity index 95% rename from pymodmilter/notifications.py rename to pymodmilter/notify.py index 6211187..3252a4e 100644 --- a/pymodmilter/notifications.py +++ b/pymodmilter/notify.py @@ -264,7 +264,9 @@ class EMailNotification(BaseNotification): logger.debug("parsing email template") # generate dict containing all template variables - template_vars.update({ + + variables = defaultdict(str, template_vars) + variables.update({ "HTML_TEXT": sanitized_text, "FROM": escape(msg["from"], quote=False), "ENVELOPE_FROM": escape(mailfrom, quote=False), @@ -276,7 +278,7 @@ class EMailNotification(BaseNotification): "SUBJECT": escape(msg["subject"], quote=False)}) # parse template - htmltext = self.template.format_map(template_vars) + htmltext = self.template.format_map(variables) msg = MIMEMultipart('related') msg["From"] = self.from_header.format_map( @@ -307,3 +309,11 @@ class EMailNotification(BaseNotification): mailer.sendmail(self.smtp_host, self.smtp_port, qid, self.mailfrom, recipient, msg.as_string(), "notification email") + + def execute(self, milter, pretend=False, + logger=logging.getLogger(__name__)): + self.notify(msg=milter.msg, qid=milter.qid, + mailfrom=milter.msginfo["mailfrom"], + recipients=milter.msginfo["rcpts"], + template_vars=milter["msginfo"]["vars"], + logger=logger) diff --git a/pymodmilter/rules.py b/pymodmilter/rule.py similarity index 98% rename from pymodmilter/rules.py rename to pymodmilter/rule.py index ef925eb..3b7ebce 100644 --- a/pymodmilter/rules.py +++ b/pymodmilter/rule.py @@ -17,7 +17,7 @@ __all__ = [ "Rule"] from pymodmilter import BaseConfig -from pymodmilter.actions import ActionConfig, Action +from pymodmilter.action import ActionConfig, Action from pymodmilter.conditions import ConditionsConfig, Conditions diff --git a/pymodmilter/storages.py b/pymodmilter/storage.py similarity index 96% rename from pymodmilter/storages.py rename to pymodmilter/storage.py index f36cb6e..a3a23c6 100644 --- a/pymodmilter/storages.py +++ b/pymodmilter/storage.py @@ -134,10 +134,12 @@ class FileMailStorage(BaseMailStorage): recipients = list(milter.msginfo["rcpts"]) subject = milter.msg["subject"] or "" - storage_id, datafile = self.add( - data(), milter.qid, mailfrom, recipients, subject) - logger.info(f"stored message in file {datafile}") - milter.msginfo["storage_id"] = storage_id + if not pretend: + storage_id, datafile = self.add( + data(), milter.qid, mailfrom, recipients, subject) + logger.info(f"stored message in file {datafile}") + milter.msginfo["vars"]["STORAGEID"] = storage_id + milter.msginfo["vars"]["DATAFILE"] = datafile def get_metadata(self, storage_id): "Return metadata of email in storage."