blob: 0f8587317c2bbc4c37c79b9112ffc281c67bcebd [file] [log] [blame]
Guido van Rossum03774bb1998-04-09 13:50:55 +00001"""A POP3 client class.
Guido van Rossum484772d1998-04-06 18:27:27 +00002
Guido van Rossum03774bb1998-04-09 13:50:55 +00003Based on the J. Myers POP3 draft, Jan. 96
Guido van Rossum484772d1998-04-06 18:27:27 +00004"""
5
Guido van Rossum98d9fd32000-02-28 15:12:25 +00006# Author: David Ascher <david_ascher@brown.edu>
7# [heavily stealing from nntplib.py]
8# Updated: Piers Lauder <piers@cs.su.oz.au> [Jul '97]
Eric S. Raymond341f9292001-02-09 06:56:56 +00009# String method conversion and test jig improvements by ESR, February 2001.
Martin v. Löwis48440b72003-10-31 12:52:35 +000010# Added the POP3_SSL class. Methods loosely based on IMAP_SSL. Hector Urtubia <urtubia@mrbook.org> Aug 2003
Guido van Rossum98d9fd32000-02-28 15:12:25 +000011
Guido van Rossum484772d1998-04-06 18:27:27 +000012# Example (see the test function at the end of this file)
13
Guido van Rossum484772d1998-04-06 18:27:27 +000014# Imports
15
Antoine Pitrou7fde5b32012-11-24 18:14:12 +010016import errno
17import re
18import socket
Steve Dower60419a72019-06-24 08:42:54 -070019import sys
Guido van Rossum484772d1998-04-06 18:27:27 +000020
Antoine Pitrou8618d742012-11-23 20:13:48 +010021try:
22 import ssl
23 HAVE_SSL = True
Brett Cannoncd171c82013-07-04 17:43:24 -040024except ImportError:
Antoine Pitrou8618d742012-11-23 20:13:48 +010025 HAVE_SSL = False
26
Thomas Wouters47b49bf2007-08-30 22:15:33 +000027__all__ = ["POP3","error_proto"]
Skip Montanaroc62c81e2001-02-12 02:00:42 +000028
Guido van Rossum484772d1998-04-06 18:27:27 +000029# Exception raised when an error or invalid response is received:
Guido van Rossum03774bb1998-04-09 13:50:55 +000030
31class error_proto(Exception): pass
Guido van Rossum484772d1998-04-06 18:27:27 +000032
33# Standard Port
34POP3_PORT = 110
35
Martin v. Löwis48440b72003-10-31 12:52:35 +000036# POP SSL PORT
37POP3_SSL_PORT = 995
38
Guido van Rossum03774bb1998-04-09 13:50:55 +000039# Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
Jeremy Hylton88d06a72007-08-29 19:08:30 +000040CR = b'\r'
41LF = b'\n'
Guido van Rossum03774bb1998-04-09 13:50:55 +000042CRLF = CR+LF
Guido van Rossum484772d1998-04-06 18:27:27 +000043
Georg Brandl7e27abb2013-10-27 07:23:53 +010044# maximal line length when calling readline(). This is to prevent
Berker Peksagf23530f2014-10-19 18:04:38 +030045# reading arbitrary length lines. RFC 1939 limits POP3 line length to
Georg Brandl7e27abb2013-10-27 07:23:53 +010046# 512 characters, including CRLF. We have selected 2048 just to be on
47# the safe side.
48_MAXLINE = 2048
49
Guido van Rossum484772d1998-04-06 18:27:27 +000050
51class POP3:
Guido van Rossum03774bb1998-04-09 13:50:55 +000052
Tim Peters2344fae2001-01-15 00:50:52 +000053 """This class supports both the minimal and optional command sets.
54 Arguments can be strings or integers (where appropriate)
55 (e.g.: retr(1) and retr('1') both work equally well.
Guido van Rossum03774bb1998-04-09 13:50:55 +000056
Tim Peters2344fae2001-01-15 00:50:52 +000057 Minimal Command Set:
58 USER name user(name)
59 PASS string pass_(string)
60 STAT stat()
61 LIST [msg] list(msg = None)
62 RETR msg retr(msg)
63 DELE msg dele(msg)
64 NOOP noop()
65 RSET rset()
66 QUIT quit()
Guido van Rossum03774bb1998-04-09 13:50:55 +000067
Tim Peters2344fae2001-01-15 00:50:52 +000068 Optional Commands (some servers support these):
69 RPOP name rpop(name)
70 APOP name digest apop(name, digest)
71 TOP msg n top(msg, n)
72 UIDL [msg] uidl(msg = None)
Antoine Pitrou25cee192012-11-23 20:07:39 +010073 CAPA capa()
Antoine Pitrou8618d742012-11-23 20:13:48 +010074 STLS stls()
R David Murrayb8cd3e42015-05-16 15:05:53 -040075 UTF8 utf8()
Guido van Rossum03774bb1998-04-09 13:50:55 +000076
Tim Peters2344fae2001-01-15 00:50:52 +000077 Raises one exception: 'error_proto'.
Guido van Rossum03774bb1998-04-09 13:50:55 +000078
Tim Peters2344fae2001-01-15 00:50:52 +000079 Instantiate with:
80 POP3(hostname, port=110)
Guido van Rossum03774bb1998-04-09 13:50:55 +000081
Tim Peters2344fae2001-01-15 00:50:52 +000082 NB: the POP protocol locks the mailbox from user
83 authorization until QUIT, so be sure to get in, suck
84 the messages, and quit, each time you access the
85 mailbox.
Guido van Rossum03774bb1998-04-09 13:50:55 +000086
Tim Peters2344fae2001-01-15 00:50:52 +000087 POP is a line-based protocol, which means large mail
88 messages consume lots of python cycles reading them
89 line-by-line.
Guido van Rossum03774bb1998-04-09 13:50:55 +000090
Tim Peters2344fae2001-01-15 00:50:52 +000091 If it's available on your mail server, use IMAP4
92 instead, it doesn't suffer from the two problems
93 above.
94 """
Guido van Rossum03774bb1998-04-09 13:50:55 +000095
Christian Heimesd3956292008-11-05 19:48:27 +000096 encoding = 'UTF-8'
Guido van Rossum03774bb1998-04-09 13:50:55 +000097
Georg Brandlf78e02b2008-06-10 17:40:04 +000098 def __init__(self, host, port=POP3_PORT,
99 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000100 self.host = host
101 self.port = port
Antoine Pitrou8618d742012-11-23 20:13:48 +0100102 self._tls_established = False
Steve Dower44f91c32019-06-27 10:47:59 -0700103 sys.audit("poplib.connect", self, host, port)
Christian Heimesd3956292008-11-05 19:48:27 +0000104 self.sock = self._create_socket(timeout)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000105 self.file = self.sock.makefile('rb')
106 self._debugging = 0
107 self.welcome = self._getresp()
Guido van Rossum484772d1998-04-06 18:27:27 +0000108
Christian Heimesd3956292008-11-05 19:48:27 +0000109 def _create_socket(self, timeout):
Dong-hee Nac39b52f2020-01-10 23:34:05 +0900110 if timeout is not None and not timeout:
111 raise ValueError('Non-blocking socket (timeout=0) is not supported')
Christian Heimesd3956292008-11-05 19:48:27 +0000112 return socket.create_connection((self.host, self.port), timeout)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000113
Tim Peters2344fae2001-01-15 00:50:52 +0000114 def _putline(self, line):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000115 if self._debugging > 1: print('*put*', repr(line))
Steve Dower44f91c32019-06-27 10:47:59 -0700116 sys.audit("poplib.putline", self, line)
Christian Heimesd3956292008-11-05 19:48:27 +0000117 self.sock.sendall(line + CRLF)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000118
Guido van Rossum484772d1998-04-06 18:27:27 +0000119
Tim Peters2344fae2001-01-15 00:50:52 +0000120 # Internal: send one command to the server (through _putline())
Guido van Rossum03774bb1998-04-09 13:50:55 +0000121
Tim Peters2344fae2001-01-15 00:50:52 +0000122 def _putcmd(self, line):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000123 if self._debugging: print('*cmd*', repr(line))
Christian Heimesd3956292008-11-05 19:48:27 +0000124 line = bytes(line, self.encoding)
Tim Peters2344fae2001-01-15 00:50:52 +0000125 self._putline(line)
Guido van Rossum484772d1998-04-06 18:27:27 +0000126
Guido van Rossum03774bb1998-04-09 13:50:55 +0000127
Tim Peters2344fae2001-01-15 00:50:52 +0000128 # Internal: return one line from the server, stripping CRLF.
129 # This is where all the CPU time of this module is consumed.
130 # Raise error_proto('-ERR EOF') if the connection is closed.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000131
Tim Peters2344fae2001-01-15 00:50:52 +0000132 def _getline(self):
Georg Brandl7e27abb2013-10-27 07:23:53 +0100133 line = self.file.readline(_MAXLINE + 1)
134 if len(line) > _MAXLINE:
135 raise error_proto('line too long')
136
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000137 if self._debugging > 1: print('*get*', repr(line))
Tim Peters2344fae2001-01-15 00:50:52 +0000138 if not line: raise error_proto('-ERR EOF')
139 octets = len(line)
140 # server can send any combination of CR & LF
141 # however, 'readline()' returns lines ending in LF
142 # so only possibilities are ...LF, ...CRLF, CR...LF
143 if line[-2:] == CRLF:
144 return line[:-2], octets
Serhiy Storchaka74a49ac2015-03-20 16:46:19 +0200145 if line[:1] == CR:
Tim Peters2344fae2001-01-15 00:50:52 +0000146 return line[1:-1], octets
147 return line[:-1], octets
Guido van Rossum03774bb1998-04-09 13:50:55 +0000148
Guido van Rossum484772d1998-04-06 18:27:27 +0000149
Tim Peters2344fae2001-01-15 00:50:52 +0000150 # Internal: get a response from the server.
151 # Raise 'error_proto' if the response doesn't start with '+'.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000152
Tim Peters2344fae2001-01-15 00:50:52 +0000153 def _getresp(self):
154 resp, o = self._getline()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000155 if self._debugging > 1: print('*resp*', repr(resp))
Christian Heimesd3956292008-11-05 19:48:27 +0000156 if not resp.startswith(b'+'):
Tim Peters2344fae2001-01-15 00:50:52 +0000157 raise error_proto(resp)
158 return resp
Guido van Rossum484772d1998-04-06 18:27:27 +0000159
Guido van Rossum03774bb1998-04-09 13:50:55 +0000160
Tim Peters2344fae2001-01-15 00:50:52 +0000161 # Internal: get a response plus following text from the server.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000162
Tim Peters2344fae2001-01-15 00:50:52 +0000163 def _getlongresp(self):
164 resp = self._getresp()
165 list = []; octets = 0
166 line, o = self._getline()
Guido van Rossum0ec34772007-09-10 00:27:13 +0000167 while line != b'.':
Christian Heimesd3956292008-11-05 19:48:27 +0000168 if line.startswith(b'..'):
Tim Peters2344fae2001-01-15 00:50:52 +0000169 o = o-1
170 line = line[1:]
171 octets = octets + o
172 list.append(line)
173 line, o = self._getline()
174 return resp, list, octets
Guido van Rossum03774bb1998-04-09 13:50:55 +0000175
Guido van Rossum484772d1998-04-06 18:27:27 +0000176
Tim Peters2344fae2001-01-15 00:50:52 +0000177 # Internal: send a command and get the response
Guido van Rossum03774bb1998-04-09 13:50:55 +0000178
Tim Peters2344fae2001-01-15 00:50:52 +0000179 def _shortcmd(self, line):
180 self._putcmd(line)
181 return self._getresp()
Guido van Rossum484772d1998-04-06 18:27:27 +0000182
Guido van Rossum03774bb1998-04-09 13:50:55 +0000183
Tim Peters2344fae2001-01-15 00:50:52 +0000184 # Internal: send a command and get the response plus following text
Guido van Rossum03774bb1998-04-09 13:50:55 +0000185
Tim Peters2344fae2001-01-15 00:50:52 +0000186 def _longcmd(self, line):
187 self._putcmd(line)
188 return self._getlongresp()
Guido van Rossum484772d1998-04-06 18:27:27 +0000189
Guido van Rossum03774bb1998-04-09 13:50:55 +0000190
Tim Peters2344fae2001-01-15 00:50:52 +0000191 # These can be useful:
192
193 def getwelcome(self):
194 return self.welcome
195
196
197 def set_debuglevel(self, level):
198 self._debugging = level
199
200
201 # Here are all the POP commands:
202
203 def user(self, user):
204 """Send user name, return response
Guido van Rossum484772d1998-04-06 18:27:27 +0000205
Tim Peters2344fae2001-01-15 00:50:52 +0000206 (should indicate password required).
207 """
208 return self._shortcmd('USER %s' % user)
Guido van Rossum484772d1998-04-06 18:27:27 +0000209
Guido van Rossum03774bb1998-04-09 13:50:55 +0000210
Tim Peters2344fae2001-01-15 00:50:52 +0000211 def pass_(self, pswd):
212 """Send password, return response
Guido van Rossum484772d1998-04-06 18:27:27 +0000213
Tim Peters2344fae2001-01-15 00:50:52 +0000214 (response includes message count, mailbox size).
Guido van Rossum03774bb1998-04-09 13:50:55 +0000215
Tim Peters2344fae2001-01-15 00:50:52 +0000216 NB: mailbox is locked by server from here to 'quit()'
217 """
218 return self._shortcmd('PASS %s' % pswd)
Guido van Rossum484772d1998-04-06 18:27:27 +0000219
Guido van Rossum03774bb1998-04-09 13:50:55 +0000220
Tim Peters2344fae2001-01-15 00:50:52 +0000221 def stat(self):
222 """Get mailbox status.
Guido van Rossum484772d1998-04-06 18:27:27 +0000223
Tim Peters2344fae2001-01-15 00:50:52 +0000224 Result is tuple of 2 ints (message count, mailbox size)
225 """
226 retval = self._shortcmd('STAT')
Eric S. Raymond341f9292001-02-09 06:56:56 +0000227 rets = retval.split()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000228 if self._debugging: print('*stat*', repr(rets))
Eric S. Raymond341f9292001-02-09 06:56:56 +0000229 numMessages = int(rets[1])
230 sizeMessages = int(rets[2])
Tim Peters2344fae2001-01-15 00:50:52 +0000231 return (numMessages, sizeMessages)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000232
Guido van Rossum03774bb1998-04-09 13:50:55 +0000233
Tim Peters2344fae2001-01-15 00:50:52 +0000234 def list(self, which=None):
235 """Request listing, return result.
Guido van Rossum484772d1998-04-06 18:27:27 +0000236
Tim Peters2344fae2001-01-15 00:50:52 +0000237 Result without a message number argument is in form
Georg Brandl2772c672005-08-05 21:01:58 +0000238 ['response', ['mesg_num octets', ...], octets].
Guido van Rossum484772d1998-04-06 18:27:27 +0000239
Tim Peters2344fae2001-01-15 00:50:52 +0000240 Result when a message number argument is given is a
241 single response: the "scan listing" for that message.
242 """
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000243 if which is not None:
Tim Peters2344fae2001-01-15 00:50:52 +0000244 return self._shortcmd('LIST %s' % which)
245 return self._longcmd('LIST')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000246
Guido van Rossum03774bb1998-04-09 13:50:55 +0000247
Tim Peters2344fae2001-01-15 00:50:52 +0000248 def retr(self, which):
249 """Retrieve whole message number 'which'.
Guido van Rossumf6ae7431998-09-02 14:42:02 +0000250
Tim Peters2344fae2001-01-15 00:50:52 +0000251 Result is in form ['response', ['line', ...], octets].
252 """
253 return self._longcmd('RETR %s' % which)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000254
Guido van Rossum484772d1998-04-06 18:27:27 +0000255
Tim Peters2344fae2001-01-15 00:50:52 +0000256 def dele(self, which):
257 """Delete message number 'which'.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000258
Tim Peters2344fae2001-01-15 00:50:52 +0000259 Result is 'response'.
260 """
261 return self._shortcmd('DELE %s' % which)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000262
Guido van Rossum484772d1998-04-06 18:27:27 +0000263
Tim Peters2344fae2001-01-15 00:50:52 +0000264 def noop(self):
265 """Does nothing.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000266
Tim Peters2344fae2001-01-15 00:50:52 +0000267 One supposes the response indicates the server is alive.
268 """
269 return self._shortcmd('NOOP')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000270
Guido van Rossum484772d1998-04-06 18:27:27 +0000271
Tim Peters2344fae2001-01-15 00:50:52 +0000272 def rset(self):
Benjamin Petersona37cfc62008-05-26 13:48:34 +0000273 """Unmark all messages marked for deletion."""
Tim Peters2344fae2001-01-15 00:50:52 +0000274 return self._shortcmd('RSET')
Guido van Rossum484772d1998-04-06 18:27:27 +0000275
Guido van Rossum03774bb1998-04-09 13:50:55 +0000276
Tim Peters2344fae2001-01-15 00:50:52 +0000277 def quit(self):
278 """Signoff: commit changes on server, unlock mailbox, close connection."""
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000279 resp = self._shortcmd('QUIT')
280 self.close()
Tim Peters2344fae2001-01-15 00:50:52 +0000281 return resp
Guido van Rossum484772d1998-04-06 18:27:27 +0000282
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000283 def close(self):
284 """Close the connection without assuming anything about it."""
Serhiy Storchaka7e7a3db2015-04-10 13:24:41 +0300285 try:
286 file = self.file
287 self.file = None
288 if file is not None:
289 file.close()
290 finally:
291 sock = self.sock
292 self.sock = None
293 if sock is not None:
294 try:
295 sock.shutdown(socket.SHUT_RDWR)
Victor Stinner83a2c282017-05-15 17:33:45 +0200296 except OSError as exc:
297 # The server might already have closed the connection.
298 # On Windows, this may result in WSAEINVAL (error 10022):
299 # An invalid operation was attempted.
300 if (exc.errno != errno.ENOTCONN
301 and getattr(exc, 'winerror', 0) != 10022):
Serhiy Storchaka7e7a3db2015-04-10 13:24:41 +0300302 raise
303 finally:
304 sock.close()
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000305
Tim Peters2344fae2001-01-15 00:50:52 +0000306 #__del__ = quit
Guido van Rossum484772d1998-04-06 18:27:27 +0000307
Guido van Rossum484772d1998-04-06 18:27:27 +0000308
Tim Peters2344fae2001-01-15 00:50:52 +0000309 # optional commands:
Guido van Rossum03774bb1998-04-09 13:50:55 +0000310
Tim Peters2344fae2001-01-15 00:50:52 +0000311 def rpop(self, user):
312 """Not sure what this does."""
313 return self._shortcmd('RPOP %s' % user)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000314
Guido van Rossum03774bb1998-04-09 13:50:55 +0000315
Jamie Davis0e6c8ee2018-03-04 00:33:32 -0500316 timestamp = re.compile(br'\+OK.[^<]*(<.*>)')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000317
Christian Heimesd3956292008-11-05 19:48:27 +0000318 def apop(self, user, password):
Tim Peters2344fae2001-01-15 00:50:52 +0000319 """Authorisation
Guido van Rossum03774bb1998-04-09 13:50:55 +0000320
Tim Peters2344fae2001-01-15 00:50:52 +0000321 - only possible if server has supplied a timestamp in initial greeting.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000322
Tim Peters2344fae2001-01-15 00:50:52 +0000323 Args:
Christian Heimesd3956292008-11-05 19:48:27 +0000324 user - mailbox user;
325 password - mailbox password.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000326
Tim Peters2344fae2001-01-15 00:50:52 +0000327 NB: mailbox is locked by server from here to 'quit()'
328 """
Mark Dickinsonea1158f2009-08-06 16:06:25 +0000329 secret = bytes(password, self.encoding)
Moshe Zadkaccc2e3d2001-01-19 19:56:27 +0000330 m = self.timestamp.match(self.welcome)
331 if not m:
Tim Peters2344fae2001-01-15 00:50:52 +0000332 raise error_proto('-ERR APOP not supported by server')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000333 import hashlib
Christian Heimesd3956292008-11-05 19:48:27 +0000334 digest = m.group(1)+secret
335 digest = hashlib.md5(digest).hexdigest()
Tim Peters2344fae2001-01-15 00:50:52 +0000336 return self._shortcmd('APOP %s %s' % (user, digest))
Guido van Rossum03774bb1998-04-09 13:50:55 +0000337
Guido van Rossum03774bb1998-04-09 13:50:55 +0000338
Tim Peters2344fae2001-01-15 00:50:52 +0000339 def top(self, which, howmuch):
340 """Retrieve message header of message number 'which'
341 and first 'howmuch' lines of message body.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000342
Tim Peters2344fae2001-01-15 00:50:52 +0000343 Result is in form ['response', ['line', ...], octets].
344 """
345 return self._longcmd('TOP %s %s' % (which, howmuch))
Guido van Rossum03774bb1998-04-09 13:50:55 +0000346
Guido van Rossum03774bb1998-04-09 13:50:55 +0000347
Tim Peters2344fae2001-01-15 00:50:52 +0000348 def uidl(self, which=None):
349 """Return message digest (unique id) list.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000350
Tim Peters2344fae2001-01-15 00:50:52 +0000351 If 'which', result contains unique id for that message
352 in the form 'response mesgnum uid', otherwise result is
353 the list ['response', ['mesgnum uid', ...], octets]
354 """
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000355 if which is not None:
Tim Peters2344fae2001-01-15 00:50:52 +0000356 return self._shortcmd('UIDL %s' % which)
357 return self._longcmd('UIDL')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000358
Antoine Pitrou25cee192012-11-23 20:07:39 +0100359
R David Murrayb8cd3e42015-05-16 15:05:53 -0400360 def utf8(self):
361 """Try to enter UTF-8 mode (see RFC 6856). Returns server response.
362 """
363 return self._shortcmd('UTF8')
364
365
Antoine Pitrou25cee192012-11-23 20:07:39 +0100366 def capa(self):
367 """Return server capabilities (RFC 2449) as a dictionary
368 >>> c=poplib.POP3('localhost')
369 >>> c.capa()
370 {'IMPLEMENTATION': ['Cyrus', 'POP3', 'server', 'v2.2.12'],
371 'TOP': [], 'LOGIN-DELAY': ['0'], 'AUTH-RESP-CODE': [],
372 'EXPIRE': ['NEVER'], 'USER': [], 'STLS': [], 'PIPELINING': [],
373 'UIDL': [], 'RESP-CODES': []}
374 >>>
375
376 Really, according to RFC 2449, the cyrus folks should avoid
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300377 having the implementation split into multiple arguments...
Antoine Pitrou25cee192012-11-23 20:07:39 +0100378 """
379 def _parsecap(line):
380 lst = line.decode('ascii').split()
381 return lst[0], lst[1:]
382
383 caps = {}
384 try:
385 resp = self._longcmd('CAPA')
386 rawcaps = resp[1]
387 for capline in rawcaps:
388 capnm, capargs = _parsecap(capline)
389 caps[capnm] = capargs
Pablo Galindo293dd232019-11-19 21:34:03 +0000390 except error_proto:
Antoine Pitrou25cee192012-11-23 20:07:39 +0100391 raise error_proto('-ERR CAPA not supported by server')
392 return caps
393
Antoine Pitrou8618d742012-11-23 20:13:48 +0100394
395 def stls(self, context=None):
396 """Start a TLS session on the active connection as specified in RFC 2595.
397
398 context - a ssl.SSLContext
399 """
400 if not HAVE_SSL:
401 raise error_proto('-ERR TLS support missing')
402 if self._tls_established:
403 raise error_proto('-ERR TLS session already established')
404 caps = self.capa()
405 if not 'STLS' in caps:
406 raise error_proto('-ERR STLS not supported by server')
407 if context is None:
Christian Heimes67986f92013-11-23 22:43:47 +0100408 context = ssl._create_stdlib_context()
Antoine Pitrou8618d742012-11-23 20:13:48 +0100409 resp = self._shortcmd('STLS')
Christian Heimes1bc70682013-12-02 20:10:50 +0100410 self.sock = context.wrap_socket(self.sock,
Benjamin Peterson7243b572014-11-23 17:04:34 -0600411 server_hostname=self.host)
Antoine Pitrou8618d742012-11-23 20:13:48 +0100412 self.file = self.sock.makefile('rb')
413 self._tls_established = True
414 return resp
415
416
417if HAVE_SSL:
Martin v. Löwis48440b72003-10-31 12:52:35 +0000418
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000419 class POP3_SSL(POP3):
420 """POP3 client class over SSL connection
Martin v. Löwis48440b72003-10-31 12:52:35 +0000421
Antoine Pitrou8618d742012-11-23 20:13:48 +0100422 Instantiate with: POP3_SSL(hostname, port=995, keyfile=None, certfile=None,
423 context=None)
Martin v. Löwis48440b72003-10-31 12:52:35 +0000424
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000425 hostname - the hostname of the pop3 over ssl server
426 port - port number
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300427 keyfile - PEM formatted file that contains your private key
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000428 certfile - PEM formatted certificate chain file
Antoine Pitrou8618d742012-11-23 20:13:48 +0100429 context - a ssl.SSLContext
Martin v. Löwis48440b72003-10-31 12:52:35 +0000430
Christian Heimesd3956292008-11-05 19:48:27 +0000431 See the methods of the parent class POP3 for more documentation.
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000432 """
Martin v. Löwis48440b72003-10-31 12:52:35 +0000433
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000434 def __init__(self, host, port=POP3_SSL_PORT, keyfile=None, certfile=None,
435 timeout=socket._GLOBAL_DEFAULT_TIMEOUT, context=None):
436 if context is not None and keyfile is not None:
437 raise ValueError("context and keyfile arguments are mutually "
438 "exclusive")
439 if context is not None and certfile is not None:
440 raise ValueError("context and certfile arguments are mutually "
441 "exclusive")
Christian Heimesd0486372016-09-10 23:23:33 +0200442 if keyfile is not None or certfile is not None:
443 import warnings
Pablo Aguiar4b5e62d2018-11-01 11:33:35 +0100444 warnings.warn("keyfile and certfile are deprecated, use a "
Christian Heimesd0486372016-09-10 23:23:33 +0200445 "custom context instead", DeprecationWarning, 2)
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000446 self.keyfile = keyfile
447 self.certfile = certfile
Christian Heimes67986f92013-11-23 22:43:47 +0100448 if context is None:
449 context = ssl._create_stdlib_context(certfile=certfile,
450 keyfile=keyfile)
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000451 self.context = context
Christian Heimesd3956292008-11-05 19:48:27 +0000452 POP3.__init__(self, host, port, timeout)
Martin v. Löwis48440b72003-10-31 12:52:35 +0000453
Christian Heimesd3956292008-11-05 19:48:27 +0000454 def _create_socket(self, timeout):
455 sock = POP3._create_socket(self, timeout)
Christian Heimes1bc70682013-12-02 20:10:50 +0100456 sock = self.context.wrap_socket(sock,
Benjamin Peterson7243b572014-11-23 17:04:34 -0600457 server_hostname=self.host)
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000458 return sock
Martin v. Löwis48440b72003-10-31 12:52:35 +0000459
Antoine Pitrou8618d742012-11-23 20:13:48 +0100460 def stls(self, keyfile=None, certfile=None, context=None):
461 """The method unconditionally raises an exception since the
462 STLS command doesn't make any sense on an already established
463 SSL/TLS session.
464 """
465 raise error_proto('-ERR TLS session already established')
466
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000467 __all__.append("POP3_SSL")
Guido van Rossum03774bb1998-04-09 13:50:55 +0000468
Guido van Rossum484772d1998-04-06 18:27:27 +0000469if __name__ == "__main__":
Eric S. Raymond341f9292001-02-09 06:56:56 +0000470 import sys
471 a = POP3(sys.argv[1])
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000472 print(a.getwelcome())
Eric S. Raymond341f9292001-02-09 06:56:56 +0000473 a.user(sys.argv[2])
474 a.pass_(sys.argv[3])
Tim Peters2344fae2001-01-15 00:50:52 +0000475 a.list()
476 (numMsgs, totalSize) = a.stat()
477 for i in range(1, numMsgs + 1):
478 (header, msg, octets) = a.retr(i)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000479 print("Message %d:" % i)
Tim Peters2344fae2001-01-15 00:50:52 +0000480 for line in msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000481 print(' ' + line)
482 print('-----------------------')
Tim Peters2344fae2001-01-15 00:50:52 +0000483 a.quit()