Просмотр исходного кода

Merge remote-tracking branch 'origin/master' into dev/email_structure

Mikael Koli 3 лет назад
Родитель
Сommit
33f48a085f
3 измененных файлов с 167 добавлено и 3 удалено
  1. 1 0
      docs/tutorials/index.rst
  2. 163 0
      docs/tutorials/testing.rst
  3. 3 3
      redmail/email/body.py

+ 1 - 0
docs/tutorials/index.rst

@@ -30,4 +30,5 @@ And see - :ref:`cookbook <cookbook>` for example use cases.
    cookbook
    config
    client
+   testing
    example

+ 163 - 0
docs/tutorials/testing.rst

@@ -0,0 +1,163 @@
+
+.. _testing:
+
+How to Test
+===========
+
+For testing purposes, it might be useful to prevent
+sending the actual email. This is especially preferable
+with unit tests. There are several ways to do this.
+
+.. note::
+
+    Red Mail extends :stdlib:`email.message.EmailMessage <email.message.html#email.message.EmailMessage>`
+    from standard library. You may use its attributes and
+    methods for testing the contents of your messages.
+
+Using get_message
+-----------------
+
+All of the arguments in method :py:meth:`.EmailSender.send`
+are passed to :py:meth:`.EmailSender.get_message` method 
+which generates the message itself. Therefore, the simplest
+solution is to use this method instead of :py:meth:`.EmailSender.send`
+in tests:
+
+.. code-block:: python
+
+    from redmail import EmailSender
+
+    # Just put something as host and port
+    email = EmailSender(host="localhost", port=0)
+
+    msg = email.get_message(
+        subject='email subject',
+        sender="me@example.com",
+        receivers=['you@example.com'],
+        text="Hi, this is an email.",
+    )
+
+    assert str(msg) == """from: me@example.com
+    subject: Some news
+    to: you@example.com
+    Content-Type: text/plain; charset="utf-8"
+    Content-Transfer-Encoding: 7bit
+    MIME-Version: 1.0
+
+    Hi, nice to meet you.
+    """
+
+Mock Server
+-----------
+
+In case changing to method :py:meth:`.EmailSender.get_message` 
+is inconvenient or it does not suit to your testing, you may
+also create a mock SMTP server that imitates an actual SMTP
+server instance:
+
+.. code-block:: python
+
+    class MockSMTP:
+
+        messages = []
+
+        def __init__(self, host, port):
+            self.host = host
+            self.port = port
+
+        def starttls(self):
+            # Called only if use_startls is True
+            return
+
+        def login(self, username, password):
+            # Log in to the server (if credentials passed)
+            self.username = username
+            self.password = password
+            return
+
+        def send_message(self, msg):
+            # Instead of sending, we just store the message
+            self.messages.append(msg)
+
+        def quit(self):
+            # Closing the connection
+            return
+
+Then to use this mock:
+
+.. code-block:: python
+
+    from redmail import EmailSender
+
+    email = EmailSender(
+        host="localhost", 
+        port=0, 
+        username="me@example.com", 
+        password="1234", 
+        cls_smtp=MockServer
+    )
+
+    email.send(
+        subject='email subject',
+        sender="me@example.com",
+        receivers=['you@example.com'],
+        text="Hi, this is an email.",
+    )
+
+    msgs = MockServer.messages
+    assert msgs == ["""from: me@example.com
+    subject: Some news
+    to: you@example.com
+    Content-Type: text/plain; charset="utf-8"
+    Content-Transfer-Encoding: 7bit
+    MIME-Version: 1.0
+
+    Hi, nice to meet you.
+    """]
+
+Note that an instance of ``MockServer`` is created 
+for each connection, often per sent email.
+
+Subclass Sender
+---------------
+
+Another option is to just subclass the sender and 
+change the email sending there:
+
+.. code-block:: python
+
+    from redmail import EmailSender
+
+    class MockSender(EmailSender):
+
+        def __init__(self, *args, **kwargs):
+            super().__init__(*args, **kwargs)
+            self.messages = []
+
+        def send_message(self, msg):
+            self.messages.append(msg)
+
+Then to use this class:
+
+.. code-block:: python
+
+    # Just put something as host and port
+    email = MockSender(host="localhost", port=0)
+
+    email.send(
+        subject='email subject',
+        sender="me@example.com",
+        receivers=['you@example.com'],
+        text="Hi, this is an email.",
+    )
+
+    msgs = email.messages
+    assert msgs == ["""from: me@example.com
+    subject: Some news
+    to: you@example.com
+    Content-Type: text/plain; charset="utf-8"
+    Content-Transfer-Encoding: 7bit
+    MIME-Version: 1.0
+
+    Hi, nice to meet you.
+    """]

+ 3 - 3
redmail/email/body.py

@@ -9,7 +9,7 @@ from pathlib import Path
 from redmail.utils import is_bytes
 from redmail.utils import import_from_string
 
-from email.utils import make_msgid
+from email.utils import make_msgid, parseaddr
 
 from jinja2.environment import Template, Environment
 
@@ -109,7 +109,7 @@ class HTMLBody(Body):
             jinja_params : dict
                 Extra Jinja parameters for the HTML.
         """
-        domain = msg["from"].split("@")[-1] if self.domain is None else self.domain
+        domain = parseaddr(msg["from"])[1].split("@")[-1] if self.domain is None else self.domain
         html, cids = self.render(
             html, 
             images=images,
@@ -244,4 +244,4 @@ class HTMLBody(Body):
                 img_content,
                 cid=cid,
                 **kwds
-            )
+            )