Example #1
0
def test_no_dry_run(mock_getpass, mock_SMTP_SSL, tmp_path):
    """Verify --no-dry-run calls SMTP sendmail()."""
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = open-smtp.example.com
        port = 465
        security = SSL/TLS
        username = admin
    """))
    sendmail_client = SendmailClient(config_path, dry_run=False)
    message = email.message_from_string(u"""
        TO: [email protected]
        SUBJECT: Testing mailmerge
        FROM: [email protected]

        Hello world
    """)

    # Mock the password entry
    mock_getpass.return_value = "password"

    # Send a message
    sendmail_client.sendmail(
        sender="*****@*****.**",
        recipients=["*****@*****.**"],
        message=message,
    )

    # Verify function calls for password and sendmail()
    assert mock_getpass.call_count == 1
    smtp = mock_SMTP_SSL.return_value.__enter__.return_value
    assert smtp.sendmail.call_count == 1
Example #2
0
def test_socket_error(mock_getpass, mock_SMTP_SSL, tmp_path):
    """Failed socket connection."""
    # Config for SSL SMTP server
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = smtp.gmail.com
        port = 465
        security = SSL/TLS
        username = awdeorio
    """))

    # Simple template
    sendmail_client = SendmailClient(config_path, dry_run=False)
    message = email.message_from_string(u"Hello world")

    # Mock the password entry
    mock_getpass.return_value = "password"

    # Configure SMTP_SSL constructor to raise an exception
    mock_SMTP_SSL.return_value.__enter__ = mock.Mock(
        side_effect=socket.error("Dummy error message")
    )

    # Send a message
    with pytest.raises(MailmergeError) as err:
        sendmail_client.sendmail(
            sender="*****@*****.**",
            recipients=["*****@*****.**"],
            message=message,
        )

    # Verify exception string
    assert "Dummy error message" in str(err.value)
Example #3
0
def test_dry_run(mock_getpass, mock_SMTP, tmp_path):
    """Verify no sendmail() calls when dry_run=True."""
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = open-smtp.example.com
        port = 25
        security = Never
    """))
    sendmail_client = SendmailClient(
        config_path,
        dry_run=True,
    )
    message = email.message_from_string(u"""
        TO: [email protected]
        SUBJECT: Testing mailmerge
        FROM: [email protected]

        Hello world
    """)

    sendmail_client.sendmail(
        sender="*****@*****.**",
        recipients=["*****@*****.**"],
        message=message,
    )

    # Verify SMTP wasn't called and password wasn't used
    assert mock_getpass.call_count == 0
    smtp = mock_SMTP.return_value.__enter__.return_value
    assert smtp.sendmail.call_count == 0
Example #4
0
def test_smtp(mock_SMTP, tmp_path):
    """Verify SMTP library calls."""
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = open-smtp.example.com
        port = 25
    """))
    sendmail_client = SendmailClient(
        config_path,
        dry_run=False,
    )
    message = email.message_from_string(u"""
        TO: [email protected]
        SUBJECT: Testing mailmerge
        FROM: [email protected]

        Hello world
    """)

    sendmail_client.sendmail(
        sender="*****@*****.**",
        recipients=["*****@*****.**"],
        message=message,
    )

    # Mock smtp object with function calls recorded
    smtp = mock_SMTP.return_value.__enter__.return_value
    assert smtp.sendmail.call_count == 1
Example #5
0
def test_security_ssl(mock_getpass, mock_SMTP_SSL, mock_SMTP, tmp_path):
    """Verify open (Never) security configuration."""
    # Config for SSL SMTP server
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = smtp.mail.umich.edu
        port = 465
        security = SSL/TLS
        username = YOUR_USERNAME_HERE
    """))

    # Simple template
    sendmail_client = SendmailClient(config_path, dry_run=False)
    message = email.message_from_string(u"Hello world")

    # Mock the password entry
    mock_getpass.return_value = "password"

    # Send a message
    sendmail_client.sendmail(
        sender="*****@*****.**",
        recipients=["*****@*****.**"],
        message=message,
    )

    # Verify SMTP library calls
    assert mock_getpass.call_count == 1
    assert mock_SMTP.call_count == 0
    assert mock_SMTP_SSL.call_count == 1
    smtp = mock_SMTP_SSL.return_value.__enter__.return_value
    assert smtp.ehlo.call_count == 0
    assert smtp.starttls.call_count == 0
    assert smtp.login.call_count == 1
    assert smtp.sendmail.call_count == 1
Example #6
0
def test_security_open_legacy(mock_SMTP, tmp_path):
    """Verify legacy "security = Never" configuration."""
    # Config SMTP server with "security = Never" legacy option
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = open-smtp.example.com
        port = 25
        security = Never
    """))

    # Simple template
    sendmail_client = SendmailClient(config_path, dry_run=False)
    message = email.message_from_string(u"Hello world")

    # Send a message
    sendmail_client.sendmail(
        sender="*****@*****.**",
        recipients=["*****@*****.**"],
        message=message,
    )

    # Verify SMTP library calls
    smtp = mock_SMTP.return_value.__enter__.return_value
    assert smtp.sendmail.call_count == 1
Example #7
0
def test_security_open(mock_getpass, mock_SMTP_SSL, mock_SMTP, tmp_path):
    """Verify open (Never) security configuration."""
    # Config for no security SMTP server
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = open-smtp.example.com
        port = 25
    """))

    # Simple template
    sendmail_client = SendmailClient(config_path, dry_run=False)
    message = email.message_from_string(u"Hello world")

    # Send a message
    sendmail_client.sendmail(
        sender="*****@*****.**",
        recipients=["*****@*****.**"],
        message=message,
    )

    # Verify SMTP library calls
    assert mock_getpass.call_count == 0
    assert mock_SMTP.call_count == 1
    assert mock_SMTP_SSL.call_count == 0
    smtp = mock_SMTP.return_value.__enter__.return_value
    assert smtp.sendmail.call_count == 1
    assert smtp.login.call_count == 0
Example #8
0
def test_smtp_login_error(mock_getpass, mock_SMTP_SSL, tmp_path):
    """Login failure."""
    # Config for SSL SMTP server
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = smtp.gmail.com
        port = 465
        security = SSL/TLS
        username = awdeorio
    """))

    # Simple template
    sendmail_client = SendmailClient(config_path, dry_run=False)
    message = email.message_from_string(u"Hello world")

    # Mock the password entry
    mock_getpass.return_value = "password"

    # Configure SMTP login() to raise an exception
    mock_SMTP_SSL.return_value.__enter__.return_value.login = mock.Mock(
        side_effect=smtplib.SMTPAuthenticationError(
            code=535,
            msg=(
                "5.7.8 Username and Password not accepted. Learn more at "
                "5.7.8  https://support.google.com/mail/?p=BadCredentials "
                "xyzxyz.32 - gsmtp"
            )
        )
    )

    # Send a message
    with pytest.raises(MailmergeError) as err:
        sendmail_client.sendmail(
            sender="*****@*****.**",
            recipients=["*****@*****.**"],
            message=message,
        )

    # Verify exception string
    assert "smtp.gmail.com:465 failed to authenticate user 'awdeorio'" in\
        str(err.value)
    assert "535" in str(err.value)
    assert (
        "5.7.8 Username and Password not accepted. Learn more at "
        "5.7.8  https://support.google.com/mail/?p=BadCredentials "
        "xyzxyz.32 - gsmtp"
    ) in str(err.value)
Example #9
0
def test_sendmail_ratelimit(mocker, tmp_path):
    """Verify SMTP library calls."""
    config_path = tmp_path / "server.conf"
    config_path.write_text(textwrap.dedent("""\
        [smtp_server]
        host = open-smtp.example.com
        port = 25
        ratelimit = 60
    """),
                           encoding="utf8")
    sendmail_client = SendmailClient(
        config_path,
        dry_run=False,
    )
    message = email.message_from_string("""
        TO: [email protected]
        SUBJECT: Testing mailmerge
        FROM: [email protected]

        Hello world
    """)

    # Mock SMTP
    mock_smtp = mocker.patch('smtplib.SMTP')

    # First message
    sendmail_client.sendmail(
        sender="*****@*****.**",
        recipients=["*****@*****.**"],
        message=message,
    )
    smtp = mock_smtp.return_value.__enter__.return_value
    assert smtp.sendmail.call_count == 1

    # Second message exceeds the rate limit, doesn't try to send a message
    with pytest.raises(MailmergeRateLimitError):
        sendmail_client.sendmail(
            sender="*****@*****.**",
            recipients=["*****@*****.**"],
            message=message,
        )
    assert smtp.sendmail.call_count == 1

    # Retry the second message after 1 s because the rate limit is 60 messages
    # per minute
    #
    # Mock the time to be 1.1 s in the future
    # Ref: https://github.com/spulec/freezegun
    now = datetime.datetime.now()
    with freezegun.freeze_time(now + datetime.timedelta(seconds=1)):
        sendmail_client.sendmail(
            sender="*****@*****.**",
            recipients=["*****@*****.**"],
            message=message,
        )
    assert smtp.sendmail.call_count == 2
Example #10
0
def test_bad_config_key(tmp_path):
    """Verify config file with bad key throws an exception."""
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        badkey = open-smtp.example.com
    """))
    with pytest.raises(MailmergeError):
        SendmailClient(config_path, dry_run=True)
Example #11
0
def test_missing_username(tmp_path):
    """Verify exception on missing username."""
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = smtp.mail.umich.edu
        port = 465
        security = SSL/TLS
    """))
    with pytest.raises(MailmergeError):
        SendmailClient(config_path, dry_run=False)
Example #12
0
def test_security_error(tmp_path):
    """Verify config file with bad security type throws an exception."""
    config_path = tmp_path/"server.conf"
    config_path.write_text(textwrap.dedent(u"""\
        [smtp_server]
        host = smtp.mail.umich.edu
        port = 465
        security = bad_value
        username = YOUR_USERNAME_HERE
    """))
    with pytest.raises(MailmergeError):
        SendmailClient(config_path, dry_run=False)