Coverage for app/backend/src/tests/test_smtp.py: 100%

21 statements  

« prev     ^ index     » next       coverage.py v7.15.1, created at 2026-07-14 20:06 +0000

1import re 

2 

3from couchers.email.rendering import template_folder 

4from couchers.email.smtp import email_proto_to_message, embed_html_relative_images 

5from couchers.proto.internal.jobs_pb2 import EmailPart, SendEmailPayload 

6 

7 

8def test_verbatim_attachment_headers(): 

9 """ 

10 Test that specified Content-Type/Content-Disposition are preserved verbatim (with original quoting). 

11 This ensures we can create attachments compatible with older email clients. 

12 """ 

13 

14 send_email_payload = SendEmailPayload( 

15 sender_name="alice", 

16 sender_email="alice@couchers.org", 

17 recipient="bob@couchers.org", 

18 subject="greeting", 

19 plain="hello", 

20 attachments=[ 

21 EmailPart( 

22 data=bytes([0, 255]), # Force base64 encoding 

23 content_type='maintype/subtype; quoted-header="value"; unquoted-header=value', 

24 content_disposition="attachment", 

25 ) 

26 ], 

27 ) 

28 

29 email_message = email_proto_to_message(send_email_payload, couchers_id="42") 

30 smtp_str = email_message.as_string() 

31 

32 expected_snippet = """ 

33Content-Type: maintype/subtype; quoted-header="value"; unquoted-header=value 

34Content-Transfer-Encoding: base64 

35Content-Disposition: attachment 

36MIME-Version: 1.0 

37 """.strip() 

38 

39 assert expected_snippet in smtp_str 

40 

41 

42def test_embed_html_relative_images() -> None: 

43 html = """ 

44 <img src="attachment_imgs/logo-grey.png"/> 

45 <img src="https://example.com/foo.png"/> 

46 """ 

47 

48 html, related_parts = embed_html_relative_images(html, base_dir=template_folder, content_id_domain="example.com") 

49 

50 content_id_match = re.search(r'src="cid:(.*@example.com)"', html) 

51 assert content_id_match is not None, "html was not modified to include content id" 

52 

53 assert "https://example.com/foo.png" in html, "Absolute image URL was replaced" 

54 

55 assert len(related_parts) == 1 

56 related_part = related_parts[0] 

57 assert related_part.content_type == 'image/png; name="logo-grey.png"' 

58 assert related_part.content_disposition == 'inline; filename="logo-grey.png"' 

59 assert related_part.content_id == f"<{content_id_match.group(1)}>"