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

31 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-27 22:00 +0000

1import re 

2 

3import pytest 

4 

5from couchers.email.rendering import template_folder 

6from couchers.email.smtp import email_proto_to_message, embed_html_relative_images 

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

8 

9 

10def test_verbatim_attachment_headers(): 

11 """ 

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

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

14 """ 

15 

16 send_email_payload = SendEmailPayload( 

17 sender_name="alice", 

18 sender_email="alice@couchers.org", 

19 recipient="bob@couchers.org", 

20 subject="greeting", 

21 plain="hello", 

22 attachments=[ 

23 EmailPart( 

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

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

26 content_disposition="attachment", 

27 ) 

28 ], 

29 ) 

30 

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

32 smtp_str = email_message.as_string() 

33 

34 expected_snippet = """ 

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

36Content-Transfer-Encoding: base64 

37Content-Disposition: attachment 

38MIME-Version: 1.0 

39 """.strip() 

40 

41 assert expected_snippet in smtp_str 

42 

43 

44def test_embed_html_relative_images() -> None: 

45 html = """ 

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

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

48 """ 

49 

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

51 

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

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

54 

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

56 

57 assert len(related_parts) == 1 

58 related_part = related_parts[0] 

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

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

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

62 

63 

64@pytest.mark.parametrize( 

65 ("html", "is_image_ref"), 

66 [ 

67 ('<img src="attachment_imgs/logo-grey.png"/>', True), 

68 ('<img\n src="attachment_imgs/logo-grey.png"/>', True), 

69 # A url that merely mentions "src=" never yields the `src="` the pattern looks for 

70 ('<a href="https://example.com/?src=foo" style="color: #777;">unsubscribe</a>', False), 

71 # ...but one that *ends* in "src=" does, and then runs on into the next attribute. Our urls end in 

72 # base64 tokens, whose "=" padding makes them end in "src=" about one time in 65k. 

73 ('<a href="https://example.com/quick-link?sig=src=" style="color: #777;">unsubscribe</a>', False), 

74 # The same url with no attribute following it, so there is no later quote to run the match into 

75 ('<a href="https://example.com/quick-link?sig=src=">unsubscribe</a>', False), 

76 ], 

77) 

78def test_embed_html_relative_images_only_matches_src_attributes(html: str, is_image_ref: bool) -> None: 

79 """Only a genuine src="" attribute is an image reference, no matter what a url in the markup contains.""" 

80 embedded_html, related_parts = embed_html_relative_images( 

81 html, base_dir=template_folder, content_id_domain="example.com" 

82 ) 

83 

84 if is_image_ref: 

85 assert len(related_parts) == 1 

86 assert related_parts[0].content_disposition == 'inline; filename="logo-grey.png"' 

87 assert f'src="cid:{related_parts[0].content_id[1:-1]}"' in embedded_html 

88 else: 

89 assert related_parts == [] 

90 assert embedded_html == html, "markup was rewritten"