test_body.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. from textwrap import dedent
  2. from redmail import EmailSender
  3. import pytest
  4. from convert import remove_extra_lines, payloads_to_dict
  5. from getpass import getpass, getuser
  6. from platform import node
  7. from convert import remove_email_extra, remove_email_content_id
  8. def test_text_message():
  9. sender = EmailSender(host=None, port=1234)
  10. msg = sender.get_message(
  11. sender="me@example.com",
  12. receivers="you@example.com",
  13. subject="Some news",
  14. text="Hi, nice to meet you.",
  15. )
  16. assert str(msg) == dedent("""
  17. from: me@example.com
  18. subject: Some news
  19. to: you@example.com
  20. Content-Type: text/plain; charset="utf-8"
  21. Content-Transfer-Encoding: 7bit
  22. MIME-Version: 1.0
  23. Hi, nice to meet you.
  24. """)[1:]
  25. def test_html_message():
  26. sender = EmailSender(host=None, port=1234)
  27. msg = sender.get_message(
  28. sender="me@example.com",
  29. receivers="you@example.com",
  30. subject="Some news",
  31. html="<h3>Hi,</h3><p>Nice to meet you</p>",
  32. )
  33. assert remove_email_content_id(str(msg)) == dedent("""
  34. from: me@example.com
  35. subject: Some news
  36. to: you@example.com
  37. Content-Type: multipart/mixed; boundary="===============<ID>=="
  38. --===============<ID>==
  39. Content-Type: multipart/alternative;
  40. boundary="===============<ID>=="
  41. --===============<ID>==
  42. Content-Type: text/html; charset="utf-8"
  43. Content-Transfer-Encoding: 7bit
  44. MIME-Version: 1.0
  45. <h3>Hi,</h3><p>Nice to meet you</p>
  46. --===============<ID>==--
  47. --===============<ID>==--
  48. """)[1:]
  49. def test_text_and_html_message():
  50. sender = EmailSender(host=None, port=1234)
  51. msg = sender.get_message(
  52. sender="me@example.com",
  53. receivers="you@example.com",
  54. subject="Some news",
  55. html="<h3>Hi,</h3><p>nice to meet you.</p>",
  56. text="Hi, nice to meet you.",
  57. )
  58. assert remove_email_content_id(str(msg)) == dedent("""
  59. from: me@example.com
  60. subject: Some news
  61. to: you@example.com
  62. MIME-Version: 1.0
  63. Content-Type: multipart/mixed; boundary="===============<ID>=="
  64. --===============<ID>==
  65. Content-Type: multipart/alternative;
  66. boundary="===============<ID>=="
  67. --===============<ID>==
  68. Content-Type: text/plain; charset="utf-8"
  69. Content-Transfer-Encoding: 7bit
  70. Hi, nice to meet you.
  71. --===============<ID>==
  72. Content-Type: text/html; charset="utf-8"
  73. Content-Transfer-Encoding: 7bit
  74. MIME-Version: 1.0
  75. <h3>Hi,</h3><p>nice to meet you.</p>
  76. --===============<ID>==--
  77. --===============<ID>==--
  78. """)[1:]
  79. @pytest.mark.parametrize(
  80. "html,expected_html,text,expected_text,extra", [
  81. pytest.param(
  82. "<h3>Hi,</h3> <p>This is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.</p>",
  83. f"<h3>Hi,</h3> <p>This is {getuser()} from {node()}. I'm really Me.</p>\n",
  84. "Hi, \nThis is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.",
  85. f"Hi, \nThis is {getuser()} from {node()}. I'm really Me.\n",
  86. None,
  87. id="With default extras"
  88. ),
  89. pytest.param(
  90. "<h3>Hi {{ receiver }},</h3> <p>This is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.</p>",
  91. f"<h3>Hi you,</h3> <p>This is overridden from {node()}. I'm really Me.</p>\n",
  92. "Hi {{ receiver }}, This is {{ user }} from {{ node }}. I'm really {{ sender.full_name }}.",
  93. f"Hi you, This is overridden from {node()}. I'm really Me.\n",
  94. {"user": "overridden", "receiver": "you"},
  95. id="Custom extra"
  96. ),
  97. ]
  98. )
  99. def test_with_jinja_params(html, text, extra, expected_html, expected_text):
  100. sender = EmailSender(host=None, port=1234)
  101. msg = sender.get_message(
  102. sender="me@gmail.com",
  103. receivers="you@gmail.com",
  104. subject="Some news",
  105. text=text,
  106. html=html,
  107. body_params=extra
  108. )
  109. # Validate structure
  110. structure = payloads_to_dict(msg)
  111. assert structure == {
  112. 'multipart/mixed': {
  113. 'multipart/alternative': {
  114. 'text/plain': structure["multipart/mixed"]["multipart/alternative"]["text/plain"],
  115. 'text/html': structure["multipart/mixed"]["multipart/alternative"]["text/html"],
  116. }
  117. }
  118. }
  119. assert "multipart/mixed" == msg.get_content_type()
  120. alternative = msg.get_payload()[0]
  121. text_part, html_part = alternative.get_payload()
  122. text = remove_email_extra(text_part.get_payload())
  123. html = remove_email_extra(html_part.get_payload())
  124. assert expected_html == html
  125. assert expected_text == text
  126. @pytest.mark.parametrize("use_jinja_obj,use_jinja", [
  127. pytest.param(None, False, id="Use arg"),
  128. pytest.param(False, None, id="Use attr"),
  129. pytest.param(True, False, id="Override"),
  130. ])
  131. def test_without_jinja(use_jinja_obj, use_jinja):
  132. html = "<h3>Hi,</h3> <p>This is {{ user }} from { node }. I'm really {{ sender.full_name }}.</p>"
  133. text = "Hi, \nThis is {{ user }} from { node }. I'm really {{ sender.full_name }}."
  134. sender = EmailSender(host=None, port=1234)
  135. sender.use_jinja = use_jinja_obj
  136. msg = sender.get_message(
  137. sender="me@example.com",
  138. receivers="you@example.com",
  139. subject="Some news",
  140. text=text,
  141. html=html,
  142. use_jinja=use_jinja,
  143. )
  144. assert remove_email_content_id(str(msg)) == dedent("""
  145. from: me@example.com
  146. subject: Some news
  147. to: you@example.com
  148. MIME-Version: 1.0
  149. Content-Type: multipart/mixed; boundary="===============<ID>=="
  150. --===============<ID>==
  151. Content-Type: multipart/alternative;
  152. boundary="===============<ID>=="
  153. --===============<ID>==
  154. Content-Type: text/plain; charset="utf-8"
  155. Content-Transfer-Encoding: 7bit
  156. Hi,
  157. This is {{ user }} from { node }. I'm really {{ sender.full_name }}.
  158. --===============<ID>==
  159. Content-Type: text/html; charset="utf-8"
  160. Content-Transfer-Encoding: quoted-printable
  161. MIME-Version: 1.0
  162. <h3>Hi,</h3> <p>This is {{ user }} from { node }. I'm really {{ sender.full_n=
  163. ame }}.</p>
  164. --===============<ID>==--
  165. --===============<ID>==--
  166. """)[1:]
  167. def test_with_error():
  168. sender = EmailSender(host=None, port=1234)
  169. try:
  170. raise RuntimeError("Deliberate failure")
  171. except:
  172. msg = sender.get_message(
  173. sender="me@gmail.com",
  174. receivers="you@gmail.com",
  175. subject="Some news",
  176. text="Error occurred \n{{ error }}",
  177. html="<h1>Error occurred: </h1>{{ error }}",
  178. )
  179. alternative = msg.get_payload()[0]
  180. text_part, html_part = alternative.get_payload()
  181. text = remove_email_extra(text_part.get_payload())
  182. html = remove_email_extra(html_part.get_payload())
  183. assert text.startswith('Error occurred\nTraceback (most recent call last):\n File "')
  184. assert text.endswith(', in test_with_error\n raise RuntimeError("Deliberate failure")\nRuntimeError: Deliberate failure\n')
  185. assert html.startswith('<h1>Error occurred: </h1>\n <div>\n <h4>Traceback (most recent call last):</h4>\n <pre><code> File &quot;')
  186. assert html.endswith(', in test_with_error\nraise RuntimeError(&quot;Deliberate failure&quot;)</code></pre>\n <span style=3D"color: red; font-weight: bold">Deliberate failure</span>: <span>RuntimeError</span>\n </div>\n')
  187. def test_set_defaults():
  188. email = EmailSender(host=None, port=1234)
  189. email.sender = 'me@gmail.com'
  190. email.receivers = ['you@gmail.com', 'they@gmail.com']
  191. email.subject = "Some email"
  192. msg = email.get_message(text="Hi, an email")
  193. assert {
  194. 'from': 'me@gmail.com',
  195. 'to': 'you@gmail.com, they@gmail.com',
  196. 'subject': 'Some email',
  197. 'Content-Type': 'text/plain; charset="utf-8"',
  198. 'Content-Transfer-Encoding': '7bit',
  199. 'MIME-Version': '1.0'
  200. } == dict(msg.items())
  201. def test_cc_bcc():
  202. email = EmailSender(host=None, port=1234)
  203. msg = email.get_message(sender="me@example.com", subject="Some email", cc=['you@example.com'], bcc=['he@example.com', 'she@example.com'])
  204. assert remove_email_content_id(str(msg)) == dedent("""
  205. from: me@example.com
  206. subject: Some email
  207. cc: you@example.com
  208. bcc: he@example.com, she@example.com
  209. """)[1:]
  210. def test_missing_subject():
  211. email = EmailSender(host=None, port=1234)
  212. with pytest.raises(ValueError):
  213. email.get_message(sender="me@example.com", receivers=['you@example.com'])
  214. def test_no_table_templates():
  215. email = EmailSender(host="localhost", port=0)
  216. assert email.default_html_theme == "modest.html"
  217. assert email.default_text_theme == "pandas.txt"
  218. email.default_html_theme = None
  219. email.default_text_theme = None
  220. msg = email.get_message(
  221. sender="me@gmail.com",
  222. receivers="you@gmail.com",
  223. subject="Some news",
  224. text="An example",
  225. html="<h1>An example</h1>"
  226. )
  227. assert dict(msg.items()) == {
  228. 'from': 'me@gmail.com',
  229. 'subject': 'Some news',
  230. 'to': 'you@gmail.com',
  231. 'MIME-Version': '1.0',
  232. 'Content-Type': 'multipart/mixed',
  233. }