diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bcc4be0..b3f4f1b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## WIP +- Add `email` action. + ## v1.9 (2020-06-12) - Add filter `Duplicate`. diff --git a/organize/actions/__init__.py b/organize/actions/__init__.py index fcb25343..6605bef0 100644 --- a/organize/actions/__init__.py +++ b/organize/actions/__init__.py @@ -1,6 +1,7 @@ from .copy import Copy from .delete import Delete from .echo import Echo +from .email import Email from .move import Move from .python import Python from .rename import Rename diff --git a/organize/actions/action.py b/organize/actions/action.py index dfdbaccf..976f3149 100644 --- a/organize/actions/action.py +++ b/organize/actions/action.py @@ -13,7 +13,7 @@ class TemplateAttributeError(Error): class Action: - pre_print_hook = None # type: Optional[Callable] + pre_print_hook = None # type: Optional[Callable] def run(self, **kwargs) -> Optional[Mapping[str, Any]]: return self.pipeline(DotDict(kwargs)) @@ -25,7 +25,11 @@ def print(self, msg) -> None: """ print a message for the user """ if callable(self.pre_print_hook): self.pre_print_hook() # pylint: disable=not-callable - print(indent("- [%s] %s" % (self.__class__.__name__, msg), " " * 4)) + # indent multiline message + lines = msg.splitlines() + print(indent("- [%s] %s" % (self.__class__.__name__, lines[0]), " " * 4)) + for line in lines[1:]: + print(indent(line, " " * 6)) @staticmethod def fill_template_tags(msg: str, args) -> str: diff --git a/organize/actions/echo.py b/organize/actions/echo.py index 8c502ba7..b97dc6c6 100644 --- a/organize/actions/echo.py +++ b/organize/actions/echo.py @@ -70,7 +70,6 @@ class Echo(Action): def __init__(self, msg) -> None: self.msg = msg - self.log = logging.getLogger(__name__) def pipeline(self, args) -> None: path = args["path"] diff --git a/organize/actions/email.py b/organize/actions/email.py new file mode 100644 index 00000000..b8d2f16e --- /dev/null +++ b/organize/actions/email.py @@ -0,0 +1,88 @@ +import logging +import smtplib +from email import encoders +from email.mime.base import MIMEBase +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.utils import formatdate +from pathlib import Path + +from .action import Action + +logger = logging.getLogger(__name__) + + +class Email(Action): + def __init__( + self, + send_from, + send_to, + subject, + message, + server="localhost", + port=587, + username="", + password="", + use_tls=True, + ) -> None: + """Compose and send email with provided info and attachments. + + Args: + send_from (str): from name + send_to (list[str]): to name(s) + subject (str): message title + message (str): message body + server (str): mail server host name + port (int): port number + username (str): server auth username + password (str): server auth password + use_tls (bool): use TLS mode + """ + self.send_from = send_from + self.send_to = send_to + self.subject = subject + self.message = message + self.server = server + self.port = port + self.username = username or send_from + self.password = password + self.use_tls = use_tls + + def pipeline(self, args) -> None: + path = args["path"] + simulate = args["simulate"] + + full_subject = self.fill_template_tags(self.subject, args) + full_message = self.fill_template_tags(self.message, args) + self.print( + "\nTo: %s\nSubj: %s\n%s" + % (", ".join(self.send_to), full_subject, full_message) + ) + if not simulate: + msg = MIMEMultipart() + msg["From"] = self.send_from + msg["To"] = ", ".join(self.send_to) + msg["Date"] = formatdate(localtime=True) + msg["Subject"] = full_subject + + msg.attach(MIMEText(full_message)) + + part = MIMEBase("application", "octet-stream") + with open(path, "rb") as f: + part.set_payload(f.read()) + encoders.encode_base64(part) + part.add_header( + "Content-Disposition", + 'attachment; filename="{}"'.format(Path(path).name), + ) + msg.attach(part) + + smtp = smtplib.SMTP(self.server, self.port) + if self.use_tls: + smtp.starttls() + smtp.login(self.username, self.password) + smtp.sendmail(self.send_from, self.send_to, msg.as_string()) + smtp.quit() + + def __str__(self) -> str: + return "Email"