192 lines
5.5 KiB
Python
192 lines
5.5 KiB
Python
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
|
|
from app.services.mail_sender import build_message, deliver_email, send_via_smtp, sign_message
|
|
from app.services.mime_body_extractor import ExtractedMimePart
|
|
|
|
|
|
def test_build_message_formats_named_sender_header():
|
|
message = build_message(
|
|
sender="suyash@gentic.email",
|
|
sender_name="Suyash Dixit",
|
|
recipients=["recipient@example.com"],
|
|
cc=[],
|
|
subject="Named sender",
|
|
body_text="Hello",
|
|
body_html=None,
|
|
)
|
|
|
|
assert message["From"] == "Suyash Dixit <suyash@gentic.email>"
|
|
|
|
|
|
def test_build_message_preserves_preformatted_transactional_sender():
|
|
message = build_message(
|
|
sender="aGentic Email <notifications@gentic.email>",
|
|
recipients=["recipient@example.com"],
|
|
cc=[],
|
|
subject="Welcome",
|
|
body_text="Hello",
|
|
body_html=None,
|
|
)
|
|
|
|
assert message["From"] == "aGentic Email <notifications@gentic.email>"
|
|
|
|
|
|
def test_build_message_adds_safe_fallback_sender_name():
|
|
message = build_message(
|
|
sender="notifications@gentic.email",
|
|
recipients=["recipient@example.com"],
|
|
cc=[],
|
|
subject="Notification",
|
|
body_text="Hello",
|
|
body_html=None,
|
|
)
|
|
|
|
assert message["From"] == "aGentic Email <notifications@gentic.email>"
|
|
|
|
|
|
def test_build_message_includes_file_attachments():
|
|
message = build_message(
|
|
sender="suyash@gentic.email",
|
|
sender_name="Suyash Dixit",
|
|
recipients=["recipient@example.com"],
|
|
cc=[],
|
|
subject="Invoice",
|
|
body_text="See attached",
|
|
body_html="<p>See attached</p>",
|
|
file_attachments=[
|
|
ExtractedMimePart(
|
|
filename="invoice.pdf",
|
|
content_type="application/pdf",
|
|
payload=b"%PDF-1.4",
|
|
)
|
|
],
|
|
)
|
|
|
|
filenames = [
|
|
part.get_filename()
|
|
for part in message.walk()
|
|
if part.get_filename()
|
|
]
|
|
assert filenames == ["invoice.pdf"]
|
|
|
|
|
|
def test_dkim_sign_uses_selector_before_domain():
|
|
message = build_message(
|
|
sender="user@ritoesis.com",
|
|
recipients=["recipient@example.com"],
|
|
cc=[],
|
|
subject="Test",
|
|
body_text="Hello",
|
|
body_html=None,
|
|
)
|
|
domain = SimpleNamespace(
|
|
domain_name="ritoesis.com",
|
|
dkim_selector="agmail",
|
|
dkim_private_key="private-key",
|
|
)
|
|
|
|
with patch(
|
|
"app.services.mail_sender.dkim.sign",
|
|
return_value=b"DKIM-Signature: test\r\n",
|
|
) as signer:
|
|
sign_message(message, domain)
|
|
|
|
assert signer.call_args.args[1] == b"agmail"
|
|
assert signer.call_args.args[2] == b"ritoesis.com"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_via_smtp_uses_configured_client_hostname():
|
|
with patch(
|
|
"app.services.mail_sender.aiosmtplib.send",
|
|
new_callable=AsyncMock,
|
|
) as send_mock:
|
|
await send_via_smtp(
|
|
b"raw",
|
|
sender="noreply@gentic.email",
|
|
recipients=["user@example.com"],
|
|
)
|
|
|
|
assert send_mock.await_args.kwargs["local_hostname"] == "backend.gentic.email"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_email_uses_bare_address_for_smtp_envelope():
|
|
domain = SimpleNamespace(
|
|
domain_name="gentic.email",
|
|
dkim_selector="agmail",
|
|
dkim_private_key="private-key",
|
|
)
|
|
with (
|
|
patch(
|
|
"app.services.mail_sender.sign_message",
|
|
return_value=b"signed",
|
|
),
|
|
patch(
|
|
"app.services.mail_sender.send_via_smtp",
|
|
new_callable=AsyncMock,
|
|
) as send_mock,
|
|
):
|
|
await deliver_email(
|
|
sender="notifications@gentic.email",
|
|
sender_name="aGentic Email",
|
|
recipients=["user@example.com"],
|
|
cc=[],
|
|
bcc=[],
|
|
subject="Welcome",
|
|
body_text="Hello",
|
|
body_html=None,
|
|
domain=domain,
|
|
)
|
|
|
|
assert send_mock.await_args.kwargs["sender"] == "notifications@gentic.email"
|
|
|
|
|
|
def test_build_message_sets_in_reply_to_and_references():
|
|
message = build_message(
|
|
sender="suyash@gentic.email",
|
|
recipients=["customer@gmail.com"],
|
|
cc=[],
|
|
subject="Re: fresh test",
|
|
body_text="human said B",
|
|
body_html=None,
|
|
in_reply_to="<CAHabc123@mail.gmail.com>",
|
|
references=["<CAHabc123@mail.gmail.com>"],
|
|
message_id="<B@gentic.email>",
|
|
)
|
|
assert message["Message-ID"] == "<B@gentic.email>"
|
|
assert message["In-Reply-To"] == "<CAHabc123@mail.gmail.com>"
|
|
assert message["References"] == "<CAHabc123@mail.gmail.com>"
|
|
raw = message.as_bytes()
|
|
assert b"In-Reply-To: <CAHabc123@mail.gmail.com>" in raw
|
|
assert b"References: <CAHabc123@mail.gmail.com>" in raw
|
|
|
|
|
|
def test_signed_mime_preserves_in_reply_to():
|
|
from unittest.mock import patch
|
|
|
|
message = build_message(
|
|
sender="suyash@gentic.email",
|
|
recipients=["customer@gmail.com"],
|
|
cc=[],
|
|
subject="Re: fresh test",
|
|
body_text="human said B",
|
|
body_html=None,
|
|
in_reply_to="<CAHabc123@mail.gmail.com>",
|
|
references=["<CAHabc123@mail.gmail.com>"],
|
|
message_id="<B@gentic.email>",
|
|
)
|
|
domain = SimpleNamespace(
|
|
domain_name="gentic.email",
|
|
dkim_selector="agmail",
|
|
dkim_private_key="private-key",
|
|
)
|
|
with patch(
|
|
"app.services.mail_sender.dkim.sign",
|
|
return_value=b"DKIM-Signature: test\r\n",
|
|
):
|
|
signed = sign_message(message, domain)
|
|
assert b"In-Reply-To: <CAHabc123@mail.gmail.com>" in signed
|