Sfoglia il codice sorgente

Merge pull request #28 from Miksus/dev/connect

add: support for sending multiple emails
Mikael Koli 4 anni fa
parent
commit
693ca593fe
3 ha cambiato i file con 104 aggiunte e 8 eliminazioni
  1. 47 1
      docs/tutorials/sending.rst
  2. 34 6
      redmail/email/sender.py
  3. 23 1
      redmail/test/email/test_send.py

+ 47 - 1
docs/tutorials/sending.rst

@@ -116,4 +116,50 @@ You can also alias the sender and receivers:
 
 Alias is an alternative text that is displayed instead of 
 the actual email addresses. The receivers can still get 
-the addresses though.
+the addresses though.
+
+.. _send-multi:
+
+Sending Multiple Emails
+-----------------------
+
+Normally Red Mail opens and closes the connection to the SMTP
+server when sending each email. If you are sending large amount
+of emails it may be beneficial to leave the connection open:
+
+.. code-block:: python
+
+    with email:
+        email.send(
+            subject='email subject',
+            sender="me@example.com",
+            receivers=['you@example.com']
+        )
+
+        email.send(
+            subject='email subject',
+            sender="me@example.com",
+            receivers=['they@example.com']
+        )
+        ...
+
+Alternatively, you may use the ``connect`` and ``close``
+methods:
+
+.. code-block:: python
+
+    try:
+        email.connect()
+        email.send(
+            subject='email subject',
+            sender="me@example.com",
+            receivers=['you@example.com']
+        )
+        email.send(
+            subject='email subject',
+            sender="me@example.com",
+            receivers=['they@example.com']
+        )
+        ...
+    finally:
+        email.close()

+ 34 - 6
redmail/email/sender.py

@@ -97,6 +97,10 @@ class EmailSender:
     kws_smtp : dict
         Keyword arguments passed to ``cls_smtp``
         when connecting to the SMTP server.
+    connection : smtplib.SMTP, None
+        Connection to the SMTP server. Created and closed
+        before and after sending each email unless there 
+        is an existing connection.
 
     Examples
     --------
@@ -151,6 +155,8 @@ class EmailSender:
         self.cls_smtp = cls_smtp
         self.kws_smtp = kwargs
         
+        self.connection = None
+
     def send(self,
              subject:Optional[str]=None,
              sender:Optional[str]=None,
@@ -369,14 +375,31 @@ class EmailSender:
 
     def send_message(self, msg:EmailMessage):
         "Send the created message"
-
-        server = self.connect()
-        server.send_message(msg)
-        
-        server.quit()
+        if self.is_alive:
+            self.connection.send_message(msg)
+        else:
+            # The connection was opened for this message
+            # thus it is also closed with this message
+            with self:
+                self.connection.send_message(msg)
     
-    def connect(self) -> smtplib.SMTP:
+    def __enter__(self):
+        self.connect()
+
+    def __exit__(self, *args):
+        self.close()
+
+    def connect(self):
         "Connect to the SMTP Server"
+        self.connection = self.get_server()
+
+    def close(self):
+        "Close (quit) the connection"
+        self.connection.quit()
+        self.connection = None
+
+    def get_server(self) -> smtplib.SMTP:
+        "Connect and get the SMTP Server"
         user = self.user_name
         password = self.password
         
@@ -388,6 +411,11 @@ class EmailSender:
             server.login(user, password)
         return server
 
+    @property
+    def is_alive(self):
+        "bool: Check if there is a connection to the SMTP server"
+        return self.connection is not None
+
     def get_params(self, sender:str) -> Dict[str, Any]:
         "Get Jinja parametes passed to both text and html bodies"
         # TODO: Add receivers to params

+ 23 - 1
redmail/test/email/test_send.py

@@ -26,12 +26,34 @@ class MockServer:
 
 def test_send():
     email = EmailSender(host="localhost", port=0, cls_smtp=MockServer)
-    # This should fail but we test everything else goes through
+    assert email.connection is None
+
     msg = email.send(
         subject="An example",
         receivers=['koli.mikael@example.com']
     )
     assert isinstance(msg, EmailMessage)
+    assert email.connection is None
+
+def test_send_multi():
+    email = EmailSender(host="localhost", port=0, cls_smtp=MockServer)
+
+    assert email.connection is None
+    with email:
+        assert email.connection is not None
+        msg = email.send(
+            subject="An example",
+            receivers=['koli.mikael@example.com']
+        )
+        assert isinstance(msg, EmailMessage)
+        assert email.connection is not None
+        msg = email.send(
+            subject="An example",
+            receivers=['koli.mikael@example.com']
+        )
+        assert isinstance(msg, EmailMessage)
+        assert email.connection is not None
+    assert email.connection is None
 
 def test_send_function():
     # This should fail but we test everything else goes through