diff --git a/examples/idle_selector_example.py b/examples/idle_selector_example.py
new file mode 100644
index 0000000..e8ff729
--- /dev/null
+++ b/examples/idle_selector_example.py
@@ -0,0 +1,36 @@
+from datetime import datetime, timedelta
+from selectors import DefaultSelector, EVENT_READ
+
+from imapclient import IMAPClient
+
+HOST = "localhost"
+USERNAME = "user"
+PASSWORD = "Tr0ub4dor&3"
+RESPONSE_TIMEOUT_SECONDS = 15
+IDLE_SECONDS = 60 * 24
+
+with IMAPClient(HOST, timeout=RESPONSE_TIMEOUT_SECONDS) as server:
+    server.login(USERNAME, PASSWORD)
+    server.select_folder("INBOX", readonly=True)
+    server.idle()
+    print(
+        "Connection is now in IDLE mode,"
+        " send yourself an email or quit with ^c"
+    )
+    try:
+        with DefaultSelector() as selector:
+            selector.register(server.socket(), EVENT_READ, None)
+            now = datetime.now
+            end_at = now() + timedelta(seconds=IDLE_SECONDS)
+            while selector.select((end_at - now()).total_seconds()):
+                responses = server.idle_check(timeout=0)
+                if not responses:
+                    raise ConnectionError(
+                        "Socket readable without data. Likely closed."
+                    )
+                print("Server sent:", responses)
+        print("IDLE time out.")
+    except KeyboardInterrupt:
+        print("")  # Newline after the typically echoed ^C.
+    server.idle_done()
+    print("IDLE mode done")
diff --git a/imapclient/imapclient.py b/imapclient/imapclient.py
index 8d58693..a7bc703 100644
--- a/imapclient/imapclient.py
+++ b/imapclient/imapclient.py
@@ -11,6 +11,7 @@ import select
 import socket
 import sys
 import re
+import warnings
 from collections import namedtuple
 from datetime import datetime, date
 from operator import itemgetter
@@ -329,10 +330,26 @@ class IMAPClient(object):
 
     def _set_read_timeout(self):
         if self._timeout is not None:
-            self._sock.settimeout(self._timeout.read)
+            self.socket().settimeout(self._timeout.read)
 
     @property
     def _sock(self):
+        warnings.warn("_sock is deprecated. Use socket().", DeprecationWarning)
+        return self.socket()
+
+    def socket(self):
+        """Returns socket used to connect to server.
+
+        The socket is provided for polling purposes only.
+        It can be used in,
+        for example, :py:meth:`selectors.BaseSelector.register`
+        and :py:meth:`asyncio.loop.add_reader` to wait for data.
+
+        .. WARNING::
+           All other uses of the returned socket are unsupported.
+           This includes reading from and writing to the socket,
+           as they are likely to break internal bookkeeping of messages.
+        """
         # In py2, imaplib has sslobj (for SSL connections), and sock for non-SSL.
         # In the py3 version it's just sock.
         return getattr(self._imap, "sslobj", self._imap.sock)
@@ -919,7 +936,7 @@ class IMAPClient(object):
              (1, b'EXISTS'),
              (1, b'FETCH', (b'FLAGS', (b'\\NotJunk',)))]
         """
-        sock = self._sock
+        sock = self.socket()
 
         # make the socket non-blocking so the timeout can be
         # implemented for this call

diff --git a/tests/test_imapclient.py b/tests/test_imapclient.py
index 4a065de..d42db68 100644
--- a/tests/test_imapclient.py
+++ b/tests/test_imapclient.py
@@ -7,6 +7,7 @@ from __future__ import unicode_literals
 import itertools
 import socket
 import sys
+import warnings
 from datetime import datetime
 import logging
 
@@ -1055,3 +1056,12 @@ class TestProtocolError(IMAPClientTest):
 
         with self.assertRaises(ProtocolError):
             client._consume_until_tagged_response(sentinel.tag, b"IDLE")
+
+class TestSocket(IMAPClientTest):
+    def test_issues_warning_for_deprecating_sock_property(self):
+        mock_sock = Mock()
+        self.client._imap.sock = self.client._imap.sslobj = mock_sock
+        with warnings.catch_warnings(record=True) as warnings_caught:
+            warnings.simplefilter("always", DeprecationWarning)
+            assert self.client._sock == self.client.socket()
+            assert len(warnings_caught) == 1

Accessing the socket used by `IMAPClient`
To watch a mailbox using IDLE, the current documentation suggests [using a busyloop](https://imapclient.readthedocs.io/en/2.2.0/advanced.html#watching-a-mailbox-using-idle) with a relatively small timeout to check for responses. A small timeout because `IMAPClient.idle_check` uses a [blocking poll](https://github.com/mjs/imapclient/blob/master/imapclient/imapclient.py#L936) with this timeout and handling `KeyboardInterrup` is not possible while it blocks. An alternative to the busy loop was suggested in <https://github.com/mjs/imapclient/issues/322>, using `select.select` to poll both the connecting socket and a separate socket.

However, in order to poll the socket, access to the underlying socket is required, available as `IMAPClient._sock`. My understanding is that this attribute is an implementation detail. Can this be relied upon? If not, is it possible to make the socket available as part of the API?
tests/test_imapclient.py::TestSocket::test_issues_warning_for_deprecating_sock_property
tests/test_imapclient.py::TestListFolders::test_blanks tests/test_imapclient.py::TestListFolders::test_empty_response tests/test_imapclient.py::TestListFolders::test_folder_encode_off tests/test_imapclient.py::TestListFolders::test_funky_characters tests/test_imapclient.py::TestListFolders::test_list_folders tests/test_imapclient.py::TestListFolders::test_list_folders_NO tests/test_imapclient.py::TestListFolders::test_list_sub_folders tests/test_imapclient.py::TestListFolders::test_list_sub_folders_NO tests/test_imapclient.py::TestListFolders::test_mixed tests/test_imapclient.py::TestListFolders::test_quoted_specials tests/test_imapclient.py::TestListFolders::test_simple tests/test_imapclient.py::TestListFolders::test_unquoted_numeric_folder_name tests/test_imapclient.py::TestListFolders::test_unquoted_numeric_folder_name_parsed_as_long tests/test_imapclient.py::TestListFolders::test_utf7_decoding tests/test_imapclient.py::TestListFolders::test_without_quotes tests/test_imapclient.py::TestFindSpecialFolder::test_find_special_folder_with_special_use tests/test_imapclient.py::TestFindSpecialFolder::test_find_special_folder_with_special_use_single_flag tests/test_imapclient.py::TestFindSpecialFolder::test_find_special_folder_without_special_use_nor_namespace tests/test_imapclient.py::TestSelectFolder::test_normal tests/test_imapclient.py::TestSelectFolder::test_unselect tests/test_imapclient.py::TestAppend::test_multiappend tests/test_imapclient.py::TestAppend::test_with_msg_time tests/test_imapclient.py::TestAppend::test_without_msg_time tests/test_imapclient.py::TestAclMethods::test_getacl tests/test_imapclient.py::TestAclMethods::test_setacl tests/test_imapclient.py::TestQuota::test__get_quota tests/test_imapclient.py::TestQuota::test_get_quota_root tests/test_imapclient.py::TestQuota::test_parse_quota tests/test_imapclient.py::TestQuota::test_set_quota tests/test_imapclient.py::TestIdleAndNoop::test_consume_until_tagged_response tests/test_imapclient.py::TestIdleAndNoop::test_idle tests/test_imapclient.py::TestIdleAndNoop::test_idle_check_blocking tests/test_imapclient.py::TestIdleAndNoop::test_idle_check_blocking_poll tests/test_imapclient.py::TestIdleAndNoop::test_idle_check_timeout tests/test_imapclient.py::TestIdleAndNoop::test_idle_check_timeout_poll tests/test_imapclient.py::TestIdleAndNoop::test_idle_check_with_data tests/test_imapclient.py::TestIdleAndNoop::test_idle_check_with_data_poll tests/test_imapclient.py::TestIdleAndNoop::test_idle_done tests/test_imapclient.py::TestIdleAndNoop::test_noop tests/test_imapclient.py::TestDebugLogging::test_IMAP_is_patched tests/test_imapclient.py::TestDebugLogging::test_redacted_password tests/test_imapclient.py::TestTimeNormalisation::test_default tests/test_imapclient.py::TestTimeNormalisation::test_pass_through tests/test_imapclient.py::TestNamespace::test_complex tests/test_imapclient.py::TestNamespace::test_folder_decoding tests/test_imapclient.py::TestNamespace::test_other_only tests/test_imapclient.py::TestNamespace::test_simple tests/test_imapclient.py::TestNamespace::test_without_folder_decoding tests/test_imapclient.py::TestCapabilities::test_caching tests/test_imapclient.py::TestCapabilities::test_decorator tests/test_imapclient.py::TestCapabilities::test_has_capability tests/test_imapclient.py::TestCapabilities::test_post_auth_request tests/test_imapclient.py::TestCapabilities::test_preauth tests/test_imapclient.py::TestCapabilities::test_server_returned_capability_after_auth tests/test_imapclient.py::TestCapabilities::test_with_starttls tests/test_imapclient.py::TestId::test_id tests/test_imapclient.py::TestId::test_invalid_parameters tests/test_imapclient.py::TestId::test_no_support tests/test_imapclient.py::TestRawCommand::test_complex tests/test_imapclient.py::TestRawCommand::test_embedded_literal tests/test_imapclient.py::TestRawCommand::test_failed_continuation_wait tests/test_imapclient.py::TestRawCommand::test_invalid_input_type tests/test_imapclient.py::TestRawCommand::test_literal_at_end tests/test_imapclient.py::TestRawCommand::test_literal_plus tests/test_imapclient.py::TestRawCommand::test_multiple_literals tests/test_imapclient.py::TestRawCommand::test_not_uid tests/test_imapclient.py::TestRawCommand::test_plain tests/test_imapclient.py::TestExpunge::test_expunge tests/test_imapclient.py::TestExpunge::test_id_expunge tests/test_imapclient.py::TestShutdown::test_shutdown tests/test_imapclient.py::TestContextManager::test_context_manager tests/test_imapclient.py::TestContextManager::test_context_manager_fail_closing tests/test_imapclient.py::TestContextManager::test_exception_inside_context_manager tests/test_imapclient.py::TestProtocolError::test_tagged_response_with_parse_error