IMAPClient 3.1.0__tar.gz → 4.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. {imapclient-3.1.0 → imapclient-4.0.1}/AUTHORS.rst +2 -0
  2. imapclient-4.0.1/IMAPClient.egg-info/PKG-INFO +195 -0
  3. imapclient-4.0.1/IMAPClient.egg-info/SOURCES.txt +43 -0
  4. imapclient-4.0.1/IMAPClient.egg-info/entry_points.txt +3 -0
  5. imapclient-4.0.1/PKG-INFO +195 -0
  6. {imapclient-3.1.0 → imapclient-4.0.1}/README.rst +12 -12
  7. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/__init__.py +0 -1
  8. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/config.py +1 -1
  9. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/imap4.py +1 -10
  10. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/imapclient.py +24 -4
  11. {imapclient-3.1.0 → imapclient-4.0.1/imapclient}/livetest.py +8 -12
  12. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/response_types.py +7 -2
  13. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/util.py +14 -1
  14. imapclient-4.0.1/imapclient/version.py +17 -0
  15. {imapclient-3.1.0 → imapclient-4.0.1}/pyproject.toml +61 -1
  16. {imapclient-3.1.0 → imapclient-4.0.1}/setup.cfg +0 -3
  17. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_imapclient.py +12 -0
  18. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_store.py +28 -14
  19. imapclient-3.1.0/IMAPClient.egg-info/PKG-INFO +0 -56
  20. imapclient-3.1.0/IMAPClient.egg-info/SOURCES.txt +0 -89
  21. imapclient-3.1.0/IMAPClient.egg-info/requires.txt +0 -3
  22. imapclient-3.1.0/MANIFEST.in +0 -8
  23. imapclient-3.1.0/NEWS.rst +0 -7
  24. imapclient-3.1.0/PKG-INFO +0 -56
  25. imapclient-3.1.0/doc/html/_modules/imapclient/exceptions.html +0 -116
  26. imapclient-3.1.0/doc/html/_modules/imapclient/imapclient.html +0 -2122
  27. imapclient-3.1.0/doc/html/_modules/imapclient/response_types.html +0 -205
  28. imapclient-3.1.0/doc/html/_modules/imapclient/testable_imapclient.html +0 -123
  29. imapclient-3.1.0/doc/html/_modules/imapclient/tls.html +0 -139
  30. imapclient-3.1.0/doc/html/_modules/index.html +0 -77
  31. imapclient-3.1.0/doc/html/_sources/advanced.rst.txt +0 -148
  32. imapclient-3.1.0/doc/html/_sources/api.rst.txt +0 -68
  33. imapclient-3.1.0/doc/html/_sources/concepts.rst.txt +0 -159
  34. imapclient-3.1.0/doc/html/_sources/contributing.rst.txt +0 -97
  35. imapclient-3.1.0/doc/html/_sources/index.rst.txt +0 -129
  36. imapclient-3.1.0/doc/html/_sources/installation.rst.txt +0 -30
  37. imapclient-3.1.0/doc/html/_sources/releases.rst.txt +0 -979
  38. imapclient-3.1.0/doc/html/_static/basic.css +0 -930
  39. imapclient-3.1.0/doc/html/_static/contents.png +0 -0
  40. imapclient-3.1.0/doc/html/_static/file.png +0 -0
  41. imapclient-3.1.0/doc/html/_static/minus.png +0 -0
  42. imapclient-3.1.0/doc/html/_static/navigation.png +0 -0
  43. imapclient-3.1.0/doc/html/_static/plus.png +0 -0
  44. imapclient-3.1.0/doc/html/_static/pygments.css +0 -74
  45. imapclient-3.1.0/doc/html/_static/sphinxdoc.css +0 -350
  46. imapclient-3.1.0/doc/html/advanced.html +0 -331
  47. imapclient-3.1.0/doc/html/api.html +0 -1196
  48. imapclient-3.1.0/doc/html/concepts.html +0 -318
  49. imapclient-3.1.0/doc/html/contributing.html +0 -210
  50. imapclient-3.1.0/doc/html/index.html +0 -340
  51. imapclient-3.1.0/doc/html/installation.html +0 -144
  52. imapclient-3.1.0/doc/html/py-modindex.html +0 -112
  53. imapclient-3.1.0/doc/html/releases.html +0 -1091
  54. imapclient-3.1.0/doc/html/search.html +0 -96
  55. imapclient-3.1.0/doc/src/advanced.rst +0 -148
  56. imapclient-3.1.0/doc/src/api.rst +0 -68
  57. imapclient-3.1.0/doc/src/concepts.rst +0 -152
  58. imapclient-3.1.0/doc/src/conf.py +0 -213
  59. imapclient-3.1.0/doc/src/contributing.rst +0 -97
  60. imapclient-3.1.0/doc/src/index.rst +0 -130
  61. imapclient-3.1.0/doc/src/installation.rst +0 -30
  62. imapclient-3.1.0/doc/src/releases.rst +0 -983
  63. imapclient-3.1.0/imapclient/version.py +0 -24
  64. imapclient-3.1.0/interact.py +0 -9
  65. imapclient-3.1.0/setup.py +0 -67
  66. imapclient-3.1.0/tests/__init__.py +0 -3
  67. imapclient-3.1.0/tests/imapclient_test.py +0 -8
  68. imapclient-3.1.0/tests/test_version.py +0 -24
  69. {imapclient-3.1.0 → imapclient-4.0.1}/COPYING +0 -0
  70. {imapclient-3.1.0 → imapclient-4.0.1}/IMAPClient.egg-info/dependency_links.txt +0 -0
  71. {imapclient-3.1.0 → imapclient-4.0.1}/IMAPClient.egg-info/top_level.txt +0 -0
  72. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/datetime_util.py +0 -0
  73. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/exceptions.py +0 -0
  74. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/fixed_offset.py +0 -0
  75. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/imap_utf7.py +0 -0
  76. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/interact.py +0 -0
  77. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/response_lexer.py +0 -0
  78. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/response_parser.py +0 -0
  79. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/testable_imapclient.py +0 -0
  80. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/tls.py +0 -0
  81. {imapclient-3.1.0 → imapclient-4.0.1}/imapclient/typing_imapclient.py +0 -0
  82. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_auth.py +0 -0
  83. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_datetime_util.py +0 -0
  84. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_enable.py +0 -0
  85. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_fixed_offset.py +0 -0
  86. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_folder_status.py +0 -0
  87. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_imap_utf7.py +0 -0
  88. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_init.py +0 -0
  89. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_response_lexer.py +0 -0
  90. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_response_parser.py +0 -0
  91. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_search.py +0 -0
  92. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_sort.py +0 -0
  93. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_starttls.py +0 -0
  94. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_thread.py +0 -0
  95. {imapclient-3.1.0 → imapclient-4.0.1}/tests/test_util_functions.py +0 -0
@@ -47,3 +47,5 @@ project:
47
47
  - @axoroll7
48
48
  - Sean Whalen
49
49
  - Peter Wienemann
50
+ - Arnout Engelen
51
+
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: IMAPClient
3
+ Version: 4.0.1
4
+ Summary: Easy-to-use, Pythonic and complete IMAP client library
5
+ Author-email: Menno Finlay-Smits <hello@menno.io>
6
+ Maintainer-email: IMAPClient Maintainers <imapclient@groups.io>
7
+ Project-URL: Homepage, https://github.com/mjs/imapclient/
8
+ Keywords: imap,client,email,mail
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Natural Language :: English
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Communications :: Email :: Post-Office :: IMAP
16
+ Classifier: Topic :: Internet
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: System :: Networking
19
+ Requires-Python: >=3.8.0
20
+ Description-Content-Type: text/x-rst
21
+ License-File: COPYING
22
+ License-File: AUTHORS.rst
23
+ Dynamic: license-file
24
+
25
+ Essentials
26
+ ----------
27
+ IMAPClient is an easy-to-use, Pythonic and complete IMAP client
28
+ library.
29
+
30
+ ========================= ========================================
31
+ Supported Python versions 3.8 - 3.14
32
+ License New BSD
33
+ Project home https://github.com/mjs/imapclient/
34
+ PyPI https://pypi.python.org/pypi/IMAPClient
35
+ Documentation https://imapclient.readthedocs.io/
36
+ Discussions https://github.com/mjs/imapclient/discussions
37
+ Test Status |build master|
38
+ ========================= ========================================
39
+
40
+ .. |build master| image:: https://github.com/mjs/imapclient/actions/workflows/main.yml/badge.svg
41
+ :target: https://github.com/mjs/imapclient/actions
42
+ :alt: master branch
43
+
44
+ Features
45
+ --------
46
+ - Arguments and return values are natural Python types.
47
+ - IMAP server responses are fully parsed and readily usable.
48
+ - IMAP unique message IDs (UIDs) are handled transparently. There is
49
+ no need to call different methods to use UIDs.
50
+ - Escaping for internationalised mailbox names is transparently
51
+ handled. Unicode mailbox names may be passed as input wherever a
52
+ folder name is accepted.
53
+ - Time zones are transparently handled including when the server and
54
+ client are in different zones.
55
+ - Convenience methods are provided for commonly used functionality.
56
+ - Exceptions are raised when errors occur.
57
+
58
+ Example
59
+ -------
60
+
61
+ .. code-block:: python
62
+
63
+ from imapclient import IMAPClient
64
+
65
+ # context manager ensures the session is cleaned up
66
+ with IMAPClient(host="imap.host.org") as client:
67
+ client.login('someone', 'secret')
68
+ client.select_folder('INBOX')
69
+
70
+ # search criteria are passed in a straightforward way
71
+ # (nesting is supported)
72
+ messages = client.search(['NOT', 'DELETED'])
73
+
74
+ # fetch selectors are passed as a simple list of strings.
75
+ response = client.fetch(messages, ['FLAGS', 'RFC822.SIZE'])
76
+
77
+ # `response` is keyed by message id and contains parsed,
78
+ # converted response items.
79
+ for message_id, data in response.items():
80
+ print('{id}: {size} bytes, flags={flags}'.format(
81
+ id=message_id,
82
+ size=data[b'RFC822.SIZE'],
83
+ flags=data[b'FLAGS']))
84
+
85
+ Why IMAPClient?
86
+ ---------------
87
+ You may ask: "why create another IMAP client library for Python?
88
+ Doesn't the Python standard library already have imaplib?".
89
+
90
+ The problem with imaplib is that it's very low-level. It expects
91
+ string values where lists or tuples would be more appropriate and
92
+ returns server responses almost unparsed. As IMAP server responses can
93
+ be quite complex this means everyone using imaplib ends up writing
94
+ their own fragile parsing routines.
95
+
96
+ Also, imaplib doesn't make good use of exceptions. This means you need
97
+ to check the return value of each call to imaplib to see if what you
98
+ just did was successful.
99
+
100
+ IMAPClient actually uses imaplib internally. This may change at some
101
+ point in the future.
102
+
103
+ Installing IMAPClient
104
+ ---------------------
105
+ IMAPClient is listed on PyPI and can be installed with `uv
106
+ <https://docs.astral.sh/uv/>`_::
107
+
108
+ uv add imapclient
109
+
110
+ More installation methods are described in the documentation.
111
+
112
+ Documentation
113
+ -------------
114
+ IMAPClient's manual is available at http://imapclient.readthedocs.io/.
115
+ Release notes can be found at
116
+ http://imapclient.readthedocs.io/#release-history.
117
+
118
+ See the `examples` directory in the root of project source for
119
+ examples of how to use IMAPClient.
120
+
121
+ Current Status
122
+ --------------
123
+ You should feel confident using IMAPClient for production purposes.
124
+
125
+ In order to clearly communicate version compatibility, IMAPClient
126
+ will strictly adhere to the `Semantic Versioning <http://semver.org>`_
127
+ scheme from version 1.0 onwards.
128
+
129
+ The project's home page is https://github.com/mjs/imapclient/ (this
130
+ currently redirects to the IMAPClient Github site). Details about
131
+ upcoming versions and planned features/fixes can be found in the issue
132
+ tracker on Github. The maintainers also blog about IMAPClient
133
+ news. Those articles can be found `here
134
+ <http://menno.io/tags/imapclient>`_.
135
+
136
+ Discussions
137
+ -----------
138
+ `Github Discussions`_ can be used to ask questions, propose changes or praise
139
+ the project maintainers :)
140
+
141
+ .. _`Github Discussions`: https://github.com/mjs/imapclient/discussions
142
+
143
+ Working on IMAPClient
144
+ ---------------------
145
+ The `contributing documentation
146
+ <http://imapclient.rtfd.io/en/master/contributing.html>`_ contains
147
+ information for those interested in improving IMAPClient.
148
+
149
+ IMAP Servers
150
+ ------------
151
+ IMAPClient is heavily tested against Dovecot, Gmail, Fastmail.fm
152
+ (who use a modified Cyrus implementation), Office365 and Yahoo. Access
153
+ to accounts on other IMAP servers/services for testing would be
154
+ greatly appreciated.
155
+
156
+ Interactive Console
157
+ -------------------
158
+ This script connects an IMAPClient instance using the command line
159
+ args given and starts an interactive session. This is useful for
160
+ exploring the IMAPClient API and testing things out, avoiding the
161
+ steps required to set up an IMAPClient instance.
162
+
163
+ The IPython shell is used if it is installed. Otherwise the
164
+ code.interact() function from the standard library is used.
165
+
166
+ The interactive console functionality can be accessed by running the
167
+ ``imapclient-interact`` script that is installed alongside IMAPClient,
168
+ or by invoking the interact module like this::
169
+
170
+ uv run python -m imapclient.interact ...
171
+
172
+ "Live" Tests
173
+ ------------
174
+ IMAPClient includes a series of live, functional tests which exercise
175
+ it against a live IMAP account. These are useful for ensuring
176
+ compatibility with a given IMAP server implementation.
177
+
178
+ The livetest functionality is run using the ``imapclient-livetest``
179
+ script that is installed alongside IMAPClient::
180
+
181
+ uv run imapclient-livetest <livetest.ini> [ optional unittest arguments ]
182
+
183
+ The configuration file format is
184
+ `described in the main documentation <http://imapclient.rtfd.io/#configuration-file-format>`_.
185
+
186
+ **WARNING**: The operations used by livetest are destructive and could
187
+ cause unintended loss of data. That said, as of version 0.9, livetest
188
+ limits its activity to a folder it creates and subfolders of that
189
+ folder. It *should* be safe to use with any IMAP account but please
190
+ don't run livetest against a truly important IMAP account.
191
+
192
+ Please include the output of imapclient-livetest with an issue if it
193
+ fails to run successfully against a particular IMAP server. Reports of
194
+ successful runs are also welcome. Please include the type and version
195
+ of the IMAP server, if known.
@@ -0,0 +1,43 @@
1
+ AUTHORS.rst
2
+ COPYING
3
+ README.rst
4
+ pyproject.toml
5
+ IMAPClient.egg-info/PKG-INFO
6
+ IMAPClient.egg-info/SOURCES.txt
7
+ IMAPClient.egg-info/dependency_links.txt
8
+ IMAPClient.egg-info/entry_points.txt
9
+ IMAPClient.egg-info/top_level.txt
10
+ imapclient/__init__.py
11
+ imapclient/config.py
12
+ imapclient/datetime_util.py
13
+ imapclient/exceptions.py
14
+ imapclient/fixed_offset.py
15
+ imapclient/imap4.py
16
+ imapclient/imap_utf7.py
17
+ imapclient/imapclient.py
18
+ imapclient/interact.py
19
+ imapclient/livetest.py
20
+ imapclient/response_lexer.py
21
+ imapclient/response_parser.py
22
+ imapclient/response_types.py
23
+ imapclient/testable_imapclient.py
24
+ imapclient/tls.py
25
+ imapclient/typing_imapclient.py
26
+ imapclient/util.py
27
+ imapclient/version.py
28
+ tests/test_auth.py
29
+ tests/test_datetime_util.py
30
+ tests/test_enable.py
31
+ tests/test_fixed_offset.py
32
+ tests/test_folder_status.py
33
+ tests/test_imap_utf7.py
34
+ tests/test_imapclient.py
35
+ tests/test_init.py
36
+ tests/test_response_lexer.py
37
+ tests/test_response_parser.py
38
+ tests/test_search.py
39
+ tests/test_sort.py
40
+ tests/test_starttls.py
41
+ tests/test_store.py
42
+ tests/test_thread.py
43
+ tests/test_util_functions.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ imapclient-interact = imapclient.interact:main
3
+ imapclient-livetest = imapclient.livetest:main
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: IMAPClient
3
+ Version: 4.0.1
4
+ Summary: Easy-to-use, Pythonic and complete IMAP client library
5
+ Author-email: Menno Finlay-Smits <hello@menno.io>
6
+ Maintainer-email: IMAPClient Maintainers <imapclient@groups.io>
7
+ Project-URL: Homepage, https://github.com/mjs/imapclient/
8
+ Keywords: imap,client,email,mail
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Natural Language :: English
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Communications :: Email :: Post-Office :: IMAP
16
+ Classifier: Topic :: Internet
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: System :: Networking
19
+ Requires-Python: >=3.8.0
20
+ Description-Content-Type: text/x-rst
21
+ License-File: COPYING
22
+ License-File: AUTHORS.rst
23
+ Dynamic: license-file
24
+
25
+ Essentials
26
+ ----------
27
+ IMAPClient is an easy-to-use, Pythonic and complete IMAP client
28
+ library.
29
+
30
+ ========================= ========================================
31
+ Supported Python versions 3.8 - 3.14
32
+ License New BSD
33
+ Project home https://github.com/mjs/imapclient/
34
+ PyPI https://pypi.python.org/pypi/IMAPClient
35
+ Documentation https://imapclient.readthedocs.io/
36
+ Discussions https://github.com/mjs/imapclient/discussions
37
+ Test Status |build master|
38
+ ========================= ========================================
39
+
40
+ .. |build master| image:: https://github.com/mjs/imapclient/actions/workflows/main.yml/badge.svg
41
+ :target: https://github.com/mjs/imapclient/actions
42
+ :alt: master branch
43
+
44
+ Features
45
+ --------
46
+ - Arguments and return values are natural Python types.
47
+ - IMAP server responses are fully parsed and readily usable.
48
+ - IMAP unique message IDs (UIDs) are handled transparently. There is
49
+ no need to call different methods to use UIDs.
50
+ - Escaping for internationalised mailbox names is transparently
51
+ handled. Unicode mailbox names may be passed as input wherever a
52
+ folder name is accepted.
53
+ - Time zones are transparently handled including when the server and
54
+ client are in different zones.
55
+ - Convenience methods are provided for commonly used functionality.
56
+ - Exceptions are raised when errors occur.
57
+
58
+ Example
59
+ -------
60
+
61
+ .. code-block:: python
62
+
63
+ from imapclient import IMAPClient
64
+
65
+ # context manager ensures the session is cleaned up
66
+ with IMAPClient(host="imap.host.org") as client:
67
+ client.login('someone', 'secret')
68
+ client.select_folder('INBOX')
69
+
70
+ # search criteria are passed in a straightforward way
71
+ # (nesting is supported)
72
+ messages = client.search(['NOT', 'DELETED'])
73
+
74
+ # fetch selectors are passed as a simple list of strings.
75
+ response = client.fetch(messages, ['FLAGS', 'RFC822.SIZE'])
76
+
77
+ # `response` is keyed by message id and contains parsed,
78
+ # converted response items.
79
+ for message_id, data in response.items():
80
+ print('{id}: {size} bytes, flags={flags}'.format(
81
+ id=message_id,
82
+ size=data[b'RFC822.SIZE'],
83
+ flags=data[b'FLAGS']))
84
+
85
+ Why IMAPClient?
86
+ ---------------
87
+ You may ask: "why create another IMAP client library for Python?
88
+ Doesn't the Python standard library already have imaplib?".
89
+
90
+ The problem with imaplib is that it's very low-level. It expects
91
+ string values where lists or tuples would be more appropriate and
92
+ returns server responses almost unparsed. As IMAP server responses can
93
+ be quite complex this means everyone using imaplib ends up writing
94
+ their own fragile parsing routines.
95
+
96
+ Also, imaplib doesn't make good use of exceptions. This means you need
97
+ to check the return value of each call to imaplib to see if what you
98
+ just did was successful.
99
+
100
+ IMAPClient actually uses imaplib internally. This may change at some
101
+ point in the future.
102
+
103
+ Installing IMAPClient
104
+ ---------------------
105
+ IMAPClient is listed on PyPI and can be installed with `uv
106
+ <https://docs.astral.sh/uv/>`_::
107
+
108
+ uv add imapclient
109
+
110
+ More installation methods are described in the documentation.
111
+
112
+ Documentation
113
+ -------------
114
+ IMAPClient's manual is available at http://imapclient.readthedocs.io/.
115
+ Release notes can be found at
116
+ http://imapclient.readthedocs.io/#release-history.
117
+
118
+ See the `examples` directory in the root of project source for
119
+ examples of how to use IMAPClient.
120
+
121
+ Current Status
122
+ --------------
123
+ You should feel confident using IMAPClient for production purposes.
124
+
125
+ In order to clearly communicate version compatibility, IMAPClient
126
+ will strictly adhere to the `Semantic Versioning <http://semver.org>`_
127
+ scheme from version 1.0 onwards.
128
+
129
+ The project's home page is https://github.com/mjs/imapclient/ (this
130
+ currently redirects to the IMAPClient Github site). Details about
131
+ upcoming versions and planned features/fixes can be found in the issue
132
+ tracker on Github. The maintainers also blog about IMAPClient
133
+ news. Those articles can be found `here
134
+ <http://menno.io/tags/imapclient>`_.
135
+
136
+ Discussions
137
+ -----------
138
+ `Github Discussions`_ can be used to ask questions, propose changes or praise
139
+ the project maintainers :)
140
+
141
+ .. _`Github Discussions`: https://github.com/mjs/imapclient/discussions
142
+
143
+ Working on IMAPClient
144
+ ---------------------
145
+ The `contributing documentation
146
+ <http://imapclient.rtfd.io/en/master/contributing.html>`_ contains
147
+ information for those interested in improving IMAPClient.
148
+
149
+ IMAP Servers
150
+ ------------
151
+ IMAPClient is heavily tested against Dovecot, Gmail, Fastmail.fm
152
+ (who use a modified Cyrus implementation), Office365 and Yahoo. Access
153
+ to accounts on other IMAP servers/services for testing would be
154
+ greatly appreciated.
155
+
156
+ Interactive Console
157
+ -------------------
158
+ This script connects an IMAPClient instance using the command line
159
+ args given and starts an interactive session. This is useful for
160
+ exploring the IMAPClient API and testing things out, avoiding the
161
+ steps required to set up an IMAPClient instance.
162
+
163
+ The IPython shell is used if it is installed. Otherwise the
164
+ code.interact() function from the standard library is used.
165
+
166
+ The interactive console functionality can be accessed by running the
167
+ ``imapclient-interact`` script that is installed alongside IMAPClient,
168
+ or by invoking the interact module like this::
169
+
170
+ uv run python -m imapclient.interact ...
171
+
172
+ "Live" Tests
173
+ ------------
174
+ IMAPClient includes a series of live, functional tests which exercise
175
+ it against a live IMAP account. These are useful for ensuring
176
+ compatibility with a given IMAP server implementation.
177
+
178
+ The livetest functionality is run using the ``imapclient-livetest``
179
+ script that is installed alongside IMAPClient::
180
+
181
+ uv run imapclient-livetest <livetest.ini> [ optional unittest arguments ]
182
+
183
+ The configuration file format is
184
+ `described in the main documentation <http://imapclient.rtfd.io/#configuration-file-format>`_.
185
+
186
+ **WARNING**: The operations used by livetest are destructive and could
187
+ cause unintended loss of data. That said, as of version 0.9, livetest
188
+ limits its activity to a folder it creates and subfolders of that
189
+ folder. It *should* be safe to use with any IMAP account but please
190
+ don't run livetest against a truly important IMAP account.
191
+
192
+ Please include the output of imapclient-livetest with an issue if it
193
+ fails to run successfully against a particular IMAP server. Reports of
194
+ successful runs are also welcome. Please include the type and version
195
+ of the IMAP server, if known.
@@ -4,7 +4,6 @@ IMAPClient is an easy-to-use, Pythonic and complete IMAP client
4
4
  library.
5
5
 
6
6
  ========================= ========================================
7
- Current version 3.0.1
8
7
  Supported Python versions 3.8 - 3.14
9
8
  License New BSD
10
9
  Project home https://github.com/mjs/imapclient/
@@ -79,9 +78,10 @@ point in the future.
79
78
 
80
79
  Installing IMAPClient
81
80
  ---------------------
82
- IMAPClient is listed on PyPI and can be installed with pip::
81
+ IMAPClient is listed on PyPI and can be installed with `uv
82
+ <https://docs.astral.sh/uv/>`_::
83
83
 
84
- pip install imapclient
84
+ uv add imapclient
85
85
 
86
86
  More installation methods are described in the documentation.
87
87
 
@@ -139,11 +139,11 @@ steps required to set up an IMAPClient instance.
139
139
  The IPython shell is used if it is installed. Otherwise the
140
140
  code.interact() function from the standard library is used.
141
141
 
142
- The interactive console functionality can be accessed running the
143
- interact.py script in the root of the source tree or by invoking the
144
- interact module like this::
142
+ The interactive console functionality can be accessed by running the
143
+ ``imapclient-interact`` script that is installed alongside IMAPClient,
144
+ or by invoking the interact module like this::
145
145
 
146
- python -m imapclient.interact ...
146
+ uv run python -m imapclient.interact ...
147
147
 
148
148
  "Live" Tests
149
149
  ------------
@@ -151,10 +151,10 @@ IMAPClient includes a series of live, functional tests which exercise
151
151
  it against a live IMAP account. These are useful for ensuring
152
152
  compatibility with a given IMAP server implementation.
153
153
 
154
- The livetest functionality are run from the root of the project source
155
- like this::
154
+ The livetest functionality is run using the ``imapclient-livetest``
155
+ script that is installed alongside IMAPClient::
156
156
 
157
- python livetest.py <livetest.ini> [ optional unittest arguments ]
157
+ uv run imapclient-livetest <livetest.ini> [ optional unittest arguments ]
158
158
 
159
159
  The configuration file format is
160
160
  `described in the main documentation <http://imapclient.rtfd.io/#configuration-file-format>`_.
@@ -165,7 +165,7 @@ limits its activity to a folder it creates and subfolders of that
165
165
  folder. It *should* be safe to use with any IMAP account but please
166
166
  don't run livetest against a truly important IMAP account.
167
167
 
168
- Please include the output of livetest.py with an issue if it fails
169
- to run successfully against a particular IMAP server. Reports of
168
+ Please include the output of imapclient-livetest with an issue if it
169
+ fails to run successfully against a particular IMAP server. Reports of
170
170
  successful runs are also welcome. Please include the type and version
171
171
  of the IMAP server, if known.
@@ -8,6 +8,5 @@
8
8
  from .imapclient import * # noqa: F401,F403
9
9
  from .response_parser import * # noqa: F401,F403
10
10
  from .tls import * # noqa: F401,F403
11
- from .version import author as __author__ # noqa: F401
12
11
  from .version import version as __version__ # noqa: F401
13
12
  from .version import version_info # noqa: F401
@@ -40,7 +40,7 @@ def get_config_defaults() -> Dict[str, Any]:
40
40
  def parse_config_file(filename: str) -> argparse.Namespace:
41
41
  """Parse INI files containing IMAP connection details.
42
42
 
43
- Used by livetest.py and interact.py
43
+ Used by imapclient.livetest and imapclient.interact
44
44
  """
45
45
 
46
46
  parser = configparser.ConfigParser(get_string_config_defaults())
@@ -10,16 +10,7 @@ from typing import Optional
10
10
  class IMAP4WithTimeout(imaplib.IMAP4):
11
11
  def __init__(self, address: str, port: int, timeout: Optional[float]) -> None:
12
12
  self._timeout = timeout
13
- imaplib.IMAP4.__init__(self, address, port)
14
-
15
- def open(
16
- self, host: str = "", port: int = 143, timeout: Optional[float] = None
17
- ) -> None:
18
- # This is overridden to make it consistent across Python versions.
19
- self.host = host
20
- self.port = port
21
- self.sock = self._create_socket(timeout)
22
- self.file = self.sock.makefile("rb")
13
+ super().__init__(address, port, timeout=timeout)
23
14
 
24
15
  def _create_socket(self, timeout: Optional[float] = None) -> socket.socket:
25
16
  return socket.create_connection(
@@ -22,7 +22,7 @@ from .datetime_util import datetime_to_INTERNALDATE, format_criteria_date
22
22
  from .imap_utf7 import decode as decode_utf7
23
23
  from .imap_utf7 import encode as encode_utf7
24
24
  from .response_parser import parse_fetch_response, parse_message_list, parse_response
25
- from .util import assert_imap_protocol, chunk, to_bytes, to_unicode
25
+ from .util import assert_imap_protocol, chunk, to_bytes, to_ints, to_unicode
26
26
 
27
27
  if hasattr(select, "poll"):
28
28
  POLL_SUPPORT = True
@@ -830,7 +830,11 @@ class IMAPClient:
830
830
  """
831
831
  logger.debug("< UNSELECT")
832
832
  # IMAP4 class has no `unselect` method so we can't use `_command_and_check` there
833
- _typ, data = self._imap._simple_command("UNSELECT")
833
+ typ, data = self._imap._simple_command("UNSELECT")
834
+ # Mirror imaplib.IMAP4.unselect: return the connection to the
835
+ # authenticated state so subsequent commands (e.g. ENABLE) are legal.
836
+ if typ == "OK":
837
+ self._imap.state = "AUTH"
834
838
  return data[0]
835
839
 
836
840
  def _process_select_response(self, resp):
@@ -1375,6 +1379,9 @@ class IMAPClient:
1375
1379
  b'INTERNALDATE': datetime.datetime(2011, 2, 24, 19, 30, 36),
1376
1380
  b'SEQ': 110}}
1377
1381
 
1382
+ Note that due to IMAP unsolicited FETCH responses the return
1383
+ value may include fields not matching the original data query.
1384
+ It is up to the caller to handle that gracefully.
1378
1385
  """
1379
1386
  if not messages:
1380
1387
  return {}
@@ -1391,7 +1398,13 @@ class IMAPClient:
1391
1398
  typ, data = self._imap._command_complete("FETCH", tag)
1392
1399
  self._checkok("fetch", typ, data)
1393
1400
  typ, data = self._imap._untagged_response(typ, data, "FETCH")
1394
- return parse_fetch_response(data, self.normalise_times, self.use_uid)
1401
+ response = parse_fetch_response(data, self.normalise_times, self.use_uid)
1402
+ # Drop unsolicited responses for other messages
1403
+ return {
1404
+ message_id: response[message_id]
1405
+ for message_id in to_ints(messages)
1406
+ if message_id in response
1407
+ }
1395
1408
 
1396
1409
  def append(self, folder, msg, flags=(), msg_time=None):
1397
1410
  """Append a message to *folder*.
@@ -1789,7 +1802,14 @@ class IMAPClient:
1789
1802
  )
1790
1803
  if silent:
1791
1804
  return None
1792
- return self._filter_fetch_dict(parse_fetch_response(data), fetch_key)
1805
+ response = parse_fetch_response(data)
1806
+ # Drop unsolicited responses for other messages
1807
+ without_unsolicited = {
1808
+ message_id: response[message_id]
1809
+ for message_id in to_ints(messages)
1810
+ if message_id in response
1811
+ }
1812
+ return self._filter_fetch_dict(without_unsolicited, fetch_key)
1793
1813
 
1794
1814
  def _filter_fetch_dict(self, fetch_dict, key):
1795
1815
  return dict((msgid, data[key]) for msgid, data in fetch_dict.items())
@@ -19,18 +19,18 @@ import unittest
19
19
  from datetime import datetime
20
20
  from email.utils import make_msgid
21
21
 
22
- from imapclient.config import create_client_from_config, parse_config_file
23
- from imapclient.exceptions import IMAPClientError
24
- from imapclient.fixed_offset import FixedOffset
25
- from imapclient.imapclient import (
22
+ from .config import create_client_from_config, parse_config_file
23
+ from .exceptions import IMAPClientError
24
+ from .fixed_offset import FixedOffset
25
+ from .imapclient import (
26
26
  _dict_bytes_normaliser,
27
27
  DELETED,
28
28
  IMAPClient,
29
29
  RECENT,
30
30
  SocketTimeout,
31
31
  )
32
- from imapclient.response_types import Address, Envelope
33
- from imapclient.util import to_bytes, to_unicode
32
+ from .response_types import Address, Envelope
33
+ from .util import to_bytes, to_unicode
34
34
 
35
35
  # TODO cleaner verbose output: avoid "__main__" and separator between classes
36
36
 
@@ -62,9 +62,7 @@ Content-Transfer-Encoding: 7bit
62
62
  Here is the second part.
63
63
 
64
64
  --===============1534046211==--
65
- """.replace(
66
- "\n", "\r\n"
67
- )
65
+ """.replace("\n", "\r\n")
68
66
 
69
67
 
70
68
  SMILE = "\u263a"
@@ -75,9 +73,7 @@ Subject: stuff
75
73
  Content-Type: text/plain; charset="UTF-8"
76
74
 
77
75
  \xe2\x98\xba
78
- """.replace(
79
- b"\n", b"\r\n"
80
- )
76
+ """.replace(b"\n", b"\r\n")
81
77
 
82
78
 
83
79
  class _TestBase(unittest.TestCase):
@@ -141,8 +141,13 @@ class BodyData(_BodyDataType):
141
141
  if TYPE_CHECKING:
142
142
  assert isinstance(part, tuple)
143
143
  parts.append(part)
144
- return cls(([cls.create(part) for part in parts],) + response[i:])
145
- return cls(response)
144
+ # The runtime representation of BodyData mixes converted
145
+ # BodyData/list items with raw, not-yet-converted response
146
+ # atoms. _BodyDataType can't precisely express this shape, so
147
+ # the construction below can't be typed exactly.
148
+ body_parts = ([cls.create(part) for part in parts],) + response[i:]
149
+ return cls(body_parts) # type: ignore[arg-type]
150
+ return cls(response) # type: ignore[arg-type]
146
151
 
147
152
  @property
148
153
  def is_multipart(self) -> bool: