Repository: mjs/imapclient

Issue:
Make SSL connections the default
In 2017 there is little reasons to connect to a mailbox over plain text.

As this is a breaking change I propose to do it for 2.0.0.

Discussion:

Patch:
diff --git a/doc/src/releases.rst b/doc/src/releases.rst
index 17c0f07..3e6c672 100644
--- a/doc/src/releases.rst
+++ b/doc/src/releases.rst
@@ -6,6 +6,7 @@
 
 Changed
 -------
+- Connections to servers use SSL/TLS by default (`ssl=True`)
 - XXX Use built-in TLS when sensible.
 - Logs are now handled by the Python logging module. `debug` and `log_file`
   are not used anymore.
diff --git a/imapclient/config.py b/imapclient/config.py
index b6d243a..ebff841 100644
--- a/imapclient/config.py
+++ b/imapclient/config.py
@@ -28,7 +28,7 @@ def get_config_defaults():
     return dict(
         username=getenv("username", None),
         password=getenv("password", None),
-        ssl=False,
+        ssl=True,
         ssl_check_hostname=True,
         ssl_verify_cert=True,
         ssl_ca_file=None,
diff --git a/imapclient/imapclient.py b/imapclient/imapclient.py
index 3776e18..3792a1f 100644
--- a/imapclient/imapclient.py
+++ b/imapclient/imapclient.py
@@ -85,16 +85,17 @@ class IMAPClient(object):
     """A connection to the IMAP server specified by *host* is made when
     this class is instantiated.
 
-    *port* defaults to 143, or 993 if *ssl* is ``True``.
+    *port* defaults to 993, or 143 if *ssl* is ``False``.
 
     If *use_uid* is ``True`` unique message UIDs be used for all calls
     that accept message ids (defaults to ``True``).
 
-    If *ssl* is ``True`` an SSL connection will be made (defaults to
-    ``False``).
+    If *ssl* is ``True`` (the default) a secure connection will be made.
+    Otherwise an insecure connection over plain text will be
+    established.
 
     If *ssl* is ``True`` the optional *ssl_context* argument can be
-    used to provide a ``backports.ssl.SSLContext`` instance used to
+    used to provide an ``ssl.SSLContext`` instance used to
     control SSL/TLS connection parameters. If this is not provided a
     sensible default context will be used.
 
@@ -122,7 +123,7 @@ class IMAPClient(object):
     AbortError = imaplib.IMAP4.abort
     ReadOnlyError = imaplib.IMAP4.readonly
 
-    def __init__(self, host, port=None, use_uid=True, ssl=False, stream=False,
+    def __init__(self, host, port=None, use_uid=True, ssl=True, stream=False,
                  ssl_context=None, timeout=None):
         if stream:
             if port is not None:
@@ -132,6 +133,11 @@ class IMAPClient(object):
         elif port is None:
             port = ssl and 993 or 143
 
+        if ssl and port == 143:
+            logger.warning("Attempting to establish an encrypted connection "
+                           "to a port (143) often used for unencrypted "
+                           "connections")
+
         self.host = host
         self.port = port
         self.ssl = ssl
@@ -146,7 +152,8 @@ class IMAPClient(object):
         self._cached_capabilities = None
 
         self._imap = self._create_IMAP4()
-        logger.debug("Connected to host %s", self.host)
+        logger.debug("Connected to host %s over %s", self.host,
+                     "SSL/TLS" if ssl else "plain text")
 
         # Small hack to make imaplib log everything to its own logger
         imaplib_logger = IMAPlibLoggerAdapter(


Test patch:
diff --git a/tests/test_init.py b/tests/test_init.py
index 6dbb0b2..f99b238 100644
--- a/tests/test_init.py
+++ b/tests/test_init.py
@@ -25,7 +25,7 @@ class TestInit(unittest.TestCase):
         fakeIMAP4 = Mock()
         self.imap4.IMAP4WithTimeout.return_value = fakeIMAP4
 
-        imap = IMAPClient('1.2.3.4', timeout=sentinel.timeout)
+        imap = IMAPClient('1.2.3.4', ssl=False, timeout=sentinel.timeout)
 
         self.assertEqual(imap._imap, fakeIMAP4)
         self.imap4.IMAP4WithTimeout.assert_called_with(
@@ -42,7 +42,7 @@ class TestInit(unittest.TestCase):
         fakeIMAP4_TLS = Mock()
         self.tls.IMAP4_TLS.return_value = fakeIMAP4_TLS
 
-        imap = IMAPClient('1.2.3.4', ssl=True, ssl_context=sentinel.context,
+        imap = IMAPClient('1.2.3.4', ssl_context=sentinel.context,
                           timeout=sentinel.timeout)
 
         self.assertEqual(imap._imap, fakeIMAP4_TLS)
@@ -58,7 +58,7 @@ class TestInit(unittest.TestCase):
     def test_stream(self):
         self.imaplib.IMAP4_stream.return_value = sentinel.IMAP4_stream
 
-        imap = IMAPClient('command', stream=True)
+        imap = IMAPClient('command', stream=True, ssl=False)
 
         self.assertEqual(imap._imap, sentinel.IMAP4_stream)
         self.imaplib.IMAP4_stream.assert_called_with('command')