Coverage for src/email_message.py: 100%

44 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-16 04:41 +0000

1"""Email message module.""" 

2 

3import time 

4import uuid 

5from email.mime.text import MIMEText 

6from typing import Any 

7 

8 

9class EmailMessage: 

10 """ 

11 Email message class for creating and managing email messages. 

12 

13 This class handles the creation of email messages with proper formatting 

14 and MIME structure for sending via SMTP. 

15 """ 

16 

17 def __init__(self, **kwargs: Any) -> None: 

18 """ 

19 Initialize email message with provided parameters and defaults. 

20 

21 Args: 

22 **kwargs: Email parameters including to, from, subject, body, etc. 

23 """ 

24 params = self._process_email_parameters(kwargs) 

25 

26 self.to = params.get("to") 

27 self.rto = params.get("rto") 

28 self.cc = params.get("cc") 

29 self.bcc = params.get("bcc") 

30 self.sender = params.get("from") 

31 self.subject = params.get("subject", "") 

32 self.body = params.get("body") 

33 self.html = params.get("html") 

34 self.date = params.get("date", self._generate_default_date()) 

35 self.charset = params.get("charset", self._get_default_charset()) 

36 self.headers = params.get("headers", {}) 

37 

38 self.message_id = self.make_key() 

39 

40 def _process_email_parameters(self, kwargs: dict[str, Any]) -> dict[str, Any]: 

41 """ 

42 Process and normalize email parameters from kwargs. 

43 

44 This function handles the transformation of keyword arguments into 

45 a normalized parameter dictionary for email message creation. 

46 

47 Args: 

48 kwargs: Raw keyword arguments passed to constructor 

49 

50 Returns: 

51 Dict containing processed email parameters 

52 """ 

53 params = {} 

54 for item in kwargs.items(): 

55 params[item[0]] = item[1] 

56 return params 

57 

58 def _generate_default_date(self) -> str: 

59 """ 

60 Generate default date string in RFC 2822 format. 

61 

62 Returns: 

63 Formatted date string for email headers 

64 """ 

65 return time.strftime("%a, %d %b %Y %H:%M:%S %z", time.gmtime()) 

66 

67 def _get_default_charset(self) -> str: 

68 """ 

69 Get default character encoding for email messages. 

70 

71 Returns: 

72 Default charset string 

73 """ 

74 return "us-ascii" 

75 

76 def make_key(self) -> str: 

77 """ 

78 Generate unique message ID. 

79 

80 Creates a unique identifier for the email message using UUID4. 

81 

82 Returns: 

83 Unique string identifier for the message 

84 """ 

85 return str(uuid.uuid4()) 

86 

87 def as_string(self) -> str: 

88 """ 

89 Return plaintext email content as string. 

90 

91 This is the main public interface for getting the formatted email 

92 message ready for sending via SMTP. 

93 

94 Returns: 

95 Complete email message as formatted string 

96 """ 

97 return self._plaintext() 

98 

99 def _plaintext(self) -> str: 

100 """ 

101 Create plaintext email content and convert to string. 

102 

103 Orchestrates the creation of MIME message structure and conversion 

104 to string format for email transmission. 

105 

106 Returns: 

107 Formatted email message string 

108 """ 

109 msg = self._create_mime_message() 

110 self._set_info(msg) 

111 return msg.as_string() 

112 

113 def _create_mime_message(self) -> MIMEText: 

114 """ 

115 Create MIME text message object. 

116 

117 Handles the creation of the core MIME structure with proper 

118 content and encoding. 

119 

120 Returns: 

121 MIMEText object ready for header setting 

122 """ 

123 # Handle None body by using empty string 

124 body_text = self.body if self.body is not None else "" 

125 return MIMEText(body_text, "plain", self.charset) 

126 

127 def _set_info(self, msg: MIMEText) -> None: 

128 """ 

129 Set email header information on MIME message. 

130 

131 Configures the essential email headers (Subject, From, To, Date) 

132 on the provided MIME message object. Handles None values gracefully. 

133 

134 Args: 

135 msg: MIMEText object to configure with headers 

136 """ 

137 msg["Subject"] = self.subject or "" 

138 msg["From"] = self.sender or "" 

139 msg["To"] = self.to or "" 

140 msg["Date"] = self.date