Coverage for .tox/coverage/lib/python3.11/site-packages/wuttjamaican/email/message.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2024-08-26 14:27 -0500

1# -*- coding: utf-8; -*- 

2################################################################################ 

3# 

4# WuttJamaican -- Base package for Wutta Framework 

5# Copyright © 2023-2024 Lance Edgar 

6# 

7# This file is part of Wutta Framework. 

8# 

9# Wutta Framework is free software: you can redistribute it and/or modify it 

10# under the terms of the GNU General Public License as published by the Free 

11# Software Foundation, either version 3 of the License, or (at your option) any 

12# later version. 

13# 

14# Wutta Framework is distributed in the hope that it will be useful, but 

15# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 

16# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 

17# more details. 

18# 

19# You should have received a copy of the GNU General Public License along with 

20# Wutta Framework. If not, see <http://www.gnu.org/licenses/>. 

21# 

22################################################################################ 

23""" 

24Email Message 

25""" 

26 

27from email.mime.multipart import MIMEMultipart 

28from email.mime.text import MIMEText 

29 

30 

31class Message: 

32 """ 

33 Represents an email message to be sent. 

34 

35 :param to: Recipient(s) for the message. This may be either a 

36 string, or list of strings. If a string, it will be converted 

37 to a list since that is how the :attr:`to` attribute tracks it. 

38 Similar logic is used for :attr:`cc` and :attr:`bcc`. 

39 

40 All attributes shown below may also be specified via constructor. 

41 

42 .. attribute:: key 

43 

44 Unique key indicating the "type" of message. An "ad-hoc" 

45 message created arbitrarily may not have/need a key; however 

46 one created via 

47 :meth:`~wuttjamaican.email.handler.EmailHandler.make_auto_message()` 

48 will always have a key. 

49 

50 This key is not used for anything within the ``Message`` class 

51 logic. It is used by 

52 :meth:`~wuttjamaican.email.handler.EmailHandler.make_auto_message()` 

53 when constructing the message, and the key is set on the final 

54 message only as a reference. 

55 

56 .. attribute:: sender 

57 

58 Sender (``From:``) address for the message. 

59 

60 .. attribute:: subject 

61 

62 Subject text for the message. 

63 

64 .. attribute:: to 

65 

66 List of ``To:`` recipients for the message. 

67 

68 .. attribute:: cc 

69 

70 List of ``Cc:`` recipients for the message. 

71 

72 .. attribute:: bcc 

73 

74 List of ``Bcc:`` recipients for the message. 

75 

76 .. attribute:: replyto 

77 

78 Optional reply-to (``Reply-To:``) address for the message. 

79 

80 .. attribute:: txt_body 

81 

82 String with the ``text/plain`` body content. 

83 

84 .. attribute:: html_body 

85 

86 String with the ``text/html`` body content. 

87 """ 

88 

89 def __init__( 

90 self, 

91 key=None, 

92 sender=None, 

93 subject=None, 

94 to=None, 

95 cc=None, 

96 bcc=None, 

97 replyto=None, 

98 txt_body=None, 

99 html_body=None, 

100 ): 

101 self.key = key 

102 self.sender = sender 

103 self.subject = subject 

104 self.set_recips('to', to) 

105 self.set_recips('cc', cc) 

106 self.set_recips('bcc', bcc) 

107 self.replyto = replyto 

108 self.txt_body = txt_body 

109 self.html_body = html_body 

110 

111 def set_recips(self, name, value): 

112 """ """ 

113 if value: 

114 if isinstance(value, str): 

115 value = [value] 

116 if not isinstance(value, (list, tuple)): 

117 raise ValueError("must specify a string, tuple or list value") 

118 else: 

119 value = [] 

120 setattr(self, name, list(value)) 

121 

122 def as_string(self): 

123 """ 

124 Returns the complete message as string. This is called from 

125 within 

126 :meth:`~wuttjamaican.email.handler.EmailHandler.deliver_message()` 

127 to obtain the SMTP payload. 

128 """ 

129 msg = None 

130 

131 if self.txt_body and self.html_body: 

132 txt = MIMEText(self.txt_body, _charset='utf_8') 

133 html = MIMEText(self.html_body, _subtype='html', _charset='utf_8') 

134 msg = MIMEMultipart(_subtype='alternative', _subparts=[txt, html]) 

135 

136 elif self.txt_body: 

137 msg = MIMEText(self.txt_body, _charset='utf_8') 

138 

139 elif self.html_body: 

140 msg = MIMEText(self.html_body, 'html', _charset='utf_8') 

141 

142 if not msg: 

143 raise ValueError("message has no body parts") 

144 

145 msg['Subject'] = self.subject 

146 msg['From'] = self.sender 

147 

148 for addr in self.to: 

149 msg['To'] = addr 

150 for addr in self.cc: 

151 msg['Cc'] = addr 

152 for addr in self.bcc: 

153 msg['Bcc'] = addr 

154 

155 if self.replyto: 

156 msg.add_header('Reply-To', self.replyto) 

157 

158 return msg.as_string()