Commit 1ccc8dab authored by Grant, Josh's avatar Grant, Josh
Browse files

Merge branch 'feature/email_attachments' into 'develop'

Feature/email attachments

See merge request nset-utilities/common-package!6
parents 0c553582 6fe43014
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -9,9 +9,4 @@ COPY src/ tmp/src
RUN set -eux && pip install --upgrade pip && \
      cd /tmp/src/ && pip install -e . && \
      pip install pytest pytest-cov


COPY ./test/test.py /test/test.py


CMD ['sh', 'tail', '-f', '/dev/null']
+3 −3
Original line number Diff line number Diff line
@@ -7,10 +7,10 @@ services:
      - ./src/:/tmp/src
      - ./test/:/test/
    env_file:
      #- ./envfile_mssql
      - ./envfile
      - ./test_envfile
    #command: ["sh", "-c", "pytest --cov=common /test/test.py"]
    command: ["sh", "-c", "test-db-conn && pytest -v --cov=common /test/test.py --cov-report term-missing"]
    #command: ["sh", "-c", "test-db-conn && pytest -v --cov=common /test/test.py"]
    command: ["python3", "/test/test.py"]
    depends_on:
      - postgres

+0 −1
Original line number Diff line number Diff line
@@ -21,4 +21,3 @@ services:
    volumes:
      - ./sql/create_tables.sql:/docker-entrypoint-initdb.d/create_tables.sql
      - ./sql/fill_tables.sql:/docker-entrypoint-initdb.d/fill_tables.sql
+57 −5
Original line number Diff line number Diff line
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import smtplib
import os
import ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from common.env import check_environment as ce
from common.logz import create_logger


def send_email(subject, text):
def send_email(subject, text, files=None):
    """ Send email to the EMAIL_RECIPIENTS env variable with the given subject
        and message body from the EMAIL_SENDER address. Email debug level is
        controlled with the EMAIL_DEBUG_LEVEL environmental variable and
@@ -18,8 +21,12 @@ def send_email(subject, text):
        :return: None
    """
    logger = create_logger()

    from_address = ce('EMAIL_SENDER')
    smtp_address = ce('SMTP_ADDRESS', 'smtp.ornl.gov')
    relay_address = ce('RELAY_ADDRESS')
    relay_port = ce('RELAY_PORT')
    relay_password = ce('RELAY_PASSWORD')
    smtp_port = ce('SMTP_PORT', 25)
    if from_address is None:
        logger.critical('Unable to send email as no EMAIL_SENDER set')
@@ -36,13 +43,58 @@ def send_email(subject, text):
    msg['To'] = to_address
    msg['Subject'] = subject
    msg.attach(MIMEText(text, 'plain'))

    # if attachment files have been passed..
    if isinstance(files, list) and len(files) > 0:
        for f in files:
            if os.path.isfile(f):
                with open(f, 'rb') as att_file:
                    part = MIMEApplication(att_file.read())
                part['Content-Disposition'] = ('attachment; filename='
                                               f'"{os.path.basename(f)}"')
                msg.attach(part)
            else:
                logger.error(f'Failed to attach file {f}. {f} is not a file.')
    elif isinstance(files, str) and len(files) > 0:
        if os.path.isfile(files):
            with open(files, 'rb') as att_file:
                part = MIMEApplication(att_file.read())
            part['Content-Disposition'] = ('attachment; filename='
                                           f'"{os.path.basename(files)}"')
            msg.attach(part)
        else:
            logger.error(f'Failed to attach file {files}. {files} is not a '
                         'file.')
    else:
        logger.error(f'Failed to attach files "{files}". Please ensure that '
                     '"files" is passed as type "list"')
    logger.info(f'Sending email to {to_address} from {from_address}')
    try:
    # try:
    if all(var is None for var in [relay_address, relay_port,
                                   relay_password]):
        with smtplib.SMTP(smtp_address, smtp_port) as server:
            server.set_debuglevel(ce('EMAIL_DEBUG_LEVEL', 0))
            server.send_message(msg)
            server.quit()
        logger.info(f'Email successfully sent to {to_address}.')
    except smtplib.SMTPException as error:
        logger.error(f'Error sending email: {error}')
    elif all(var is not None for var in [relay_address, relay_port,
                                         relay_address]):
        # allow ssl connection
        context = ssl.create_default_context()
        with smtplib.SMTP(relay_address, relay_port) as conn:
            conn.ehlo()
            conn.starttls(context=context)
            conn.login(from_address, relay_password)
            conn.send_message(msg)
            conn.quit()
        logger.info(f'Email successfully sent to {to_address}.')
    else:
        logger.error("Misconfigured environment variables detected. " +
                     "Please specify either all environment variables " +
                     "for relay addresses or none of them. Relay " +
                     "environment variables: 'RELAY_ADDRESS', " +
                     "'RELAY_PORT', 'RELAY_PASSWORD'")
    # except smtplib.SMTPException as error:
    #     logger.error(f'Error sending email: {error}')

    return None
+28 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ from common.mixins.postgres import PostgresMixin
from common.mixins.mssql import MSSQLMixin
from common.mixins.postgres_logger import PostgresLoggerMixin
from common.logz import create_logger
from common.mail import send_email


class DBPG(Database, PostgresMixin):
@@ -224,5 +225,32 @@ class LogzTestCase(unittest.TestCase):
        # test empty list:
        plm.write_log_collection_to_database()

class MailTestCase(unittest.TestCase):
    """MailTestCase."""

    def test_send_email(self):
        """Test to make sure that then send_mail function can actually send
        mail"""
        send_email("TEST SUBJECT", "THIS IS A TEST MESSAGE")

    def test_send_email_attachment(self):
        """Test to make sure that we can send attachments.."""
        ATTACHMENT_PATHS = ["/test/test_attachments/test_attachment.txt",
                            "/test/test_attachments/test_attachment2.txt"]
        ATTACHMENT_PATHS_W_BAD_FILE = [
            "/test/test_attachments/test_attachment.txt",
            "/this/is/not/a/real/file/path.txt"]
        send_email(
            "TEST SUBJECT WITH ATTACHMENT", "THIS IS A TEST MESSAGE",
            files=[ATTACHMENT_PATHS[0]]
        )
        send_email("TEST SUBJECT MULTI-ATTACHMENTS", "TEST MESSAGE",
                   files=ATTACHMENT_PATHS)
        send_email("TEST SUBJECT WITH BAD PATH", "TEST MESSAGE",
                   files=ATTACHMENT_PATHS_W_BAD_FILE)
        send_email("TEST SUBJECT WITH STRING FILE PATH", "TEST MESSAGE",
                   files=ATTACHMENT_PATHS[0])


if __name__ == "__main__":
    unittest.main(verbosity=2)
Loading