blob: 6bcfa5cfeba37bfb9ce06da52ec905c8d4fbc513 [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
Guido van Rossum484772d1998-04-06 18:27:27 +000019
Antoine Pitrou8618d742012-11-23 20:13:48 +010020try:
21 import ssl
22 HAVE_SSL = True
Brett Cannoncd171c82013-07-04 17:43:24 -040023except ImportError:
Antoine Pitrou8618d742012-11-23 20:13:48 +010024 HAVE_SSL = False
25
Thomas Wouters47b49bf2007-08-30 22:15:33 +000026__all__ = ["POP3","error_proto"]
Skip Montanaroc62c81e2001-02-12 02:00:42 +000027
Guido van Rossum484772d1998-04-06 18:27:27 +000028# Exception raised when an error or invalid response is received:
Guido van Rossum03774bb1998-04-09 13:50:55 +000029
30class error_proto(Exception): pass
Guido van Rossum484772d1998-04-06 18:27:27 +000031
32# Standard Port
33POP3_PORT = 110
34
Martin v. Löwis48440b72003-10-31 12:52:35 +000035# POP SSL PORT
36POP3_SSL_PORT = 995
37
Guido van Rossum03774bb1998-04-09 13:50:55 +000038# Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
Jeremy Hylton88d06a72007-08-29 19:08:30 +000039CR = b'\r'
40LF = b'\n'
Guido van Rossum03774bb1998-04-09 13:50:55 +000041CRLF = CR+LF
Guido van Rossum484772d1998-04-06 18:27:27 +000042
Georg Brandl7e27abb2013-10-27 07:23:53 +010043# maximal line length when calling readline(). This is to prevent
Berker Peksagf23530f2014-10-19 18:04:38 +030044# reading arbitrary length lines. RFC 1939 limits POP3 line length to
Georg Brandl7e27abb2013-10-27 07:23:53 +010045# 512 characters, including CRLF. We have selected 2048 just to be on
46# the safe side.
47_MAXLINE = 2048
48
Guido van Rossum484772d1998-04-06 18:27:27 +000049
50class POP3:
Guido van Rossum03774bb1998-04-09 13:50:55 +000051
Tim Peters2344fae2001-01-15 00:50:52 +000052 """This class supports both the minimal and optional command sets.
53 Arguments can be strings or integers (where appropriate)
54 (e.g.: retr(1) and retr('1') both work equally well.
Guido van Rossum03774bb1998-04-09 13:50:55 +000055
Tim Peters2344fae2001-01-15 00:50:52 +000056 Minimal Command Set:
57 USER name user(name)
58 PASS string pass_(string)
59 STAT stat()
60 LIST [msg] list(msg = None)
61 RETR msg retr(msg)
62 DELE msg dele(msg)
63 NOOP noop()
64 RSET rset()
65 QUIT quit()
Guido van Rossum03774bb1998-04-09 13:50:55 +000066
Tim Peters2344fae2001-01-15 00:50:52 +000067 Optional Commands (some servers support these):
68 RPOP name rpop(name)
69 APOP name digest apop(name, digest)
70 TOP msg n top(msg, n)
71 UIDL [msg] uidl(msg = None)
Antoine Pitrou25cee192012-11-23 20:07:39 +010072 CAPA capa()
Antoine Pitrou8618d742012-11-23 20:13:48 +010073 STLS stls()
R David Murrayb8cd3e42015-05-16 15:05:53 -040074 UTF8 utf8()
Guido van Rossum03774bb1998-04-09 13:50:55 +000075
Tim Peters2344fae2001-01-15 00:50:52 +000076 Raises one exception: 'error_proto'.
Guido van Rossum03774bb1998-04-09 13:50:55 +000077
Tim Peters2344fae2001-01-15 00:50:52 +000078 Instantiate with:
79 POP3(hostname, port=110)
Guido van Rossum03774bb1998-04-09 13:50:55 +000080
Tim Peters2344fae2001-01-15 00:50:52 +000081 NB: the POP protocol locks the mailbox from user
82 authorization until QUIT, so be sure to get in, suck
83 the messages, and quit, each time you access the
84 mailbox.
Guido van Rossum03774bb1998-04-09 13:50:55 +000085
Tim Peters2344fae2001-01-15 00:50:52 +000086 POP is a line-based protocol, which means large mail
87 messages consume lots of python cycles reading them
88 line-by-line.
Guido van Rossum03774bb1998-04-09 13:50:55 +000089
Tim Peters2344fae2001-01-15 00:50:52 +000090 If it's available on your mail server, use IMAP4
91 instead, it doesn't suffer from the two problems
92 above.
93 """
Guido van Rossum03774bb1998-04-09 13:50:55 +000094
Christian Heimesd3956292008-11-05 19:48:27 +000095 encoding = 'UTF-8'
Guido van Rossum03774bb1998-04-09 13:50:55 +000096
Georg Brandlf78e02b2008-06-10 17:40:04 +000097 def __init__(self, host, port=POP3_PORT,
98 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Martin v. Löwis4eb59402001-07-26 13:37:33 +000099 self.host = host
100 self.port = port
Antoine Pitrou8618d742012-11-23 20:13:48 +0100101 self._tls_established = False
Christian Heimesd3956292008-11-05 19:48:27 +0000102 self.sock = self._create_socket(timeout)
Martin v. Löwis4eb59402001-07-26 13:37:33 +0000103 self.file = self.sock.makefile('rb')
104 self._debugging = 0
105 self.welcome = self._getresp()
Guido van Rossum484772d1998-04-06 18:27:27 +0000106
Christian Heimesd3956292008-11-05 19:48:27 +0000107 def _create_socket(self, timeout):
108 return socket.create_connection((self.host, self.port), timeout)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000109
Tim Peters2344fae2001-01-15 00:50:52 +0000110 def _putline(self, line):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000111 if self._debugging > 1: print('*put*', repr(line))
Christian Heimesd3956292008-11-05 19:48:27 +0000112 self.sock.sendall(line + CRLF)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000113
Guido van Rossum484772d1998-04-06 18:27:27 +0000114
Tim Peters2344fae2001-01-15 00:50:52 +0000115 # Internal: send one command to the server (through _putline())
Guido van Rossum03774bb1998-04-09 13:50:55 +0000116
Tim Peters2344fae2001-01-15 00:50:52 +0000117 def _putcmd(self, line):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000118 if self._debugging: print('*cmd*', repr(line))
Christian Heimesd3956292008-11-05 19:48:27 +0000119 line = bytes(line, self.encoding)
Tim Peters2344fae2001-01-15 00:50:52 +0000120 self._putline(line)
Guido van Rossum484772d1998-04-06 18:27:27 +0000121
Guido van Rossum03774bb1998-04-09 13:50:55 +0000122
Tim Peters2344fae2001-01-15 00:50:52 +0000123 # Internal: return one line from the server, stripping CRLF.
124 # This is where all the CPU time of this module is consumed.
125 # Raise error_proto('-ERR EOF') if the connection is closed.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000126
Tim Peters2344fae2001-01-15 00:50:52 +0000127 def _getline(self):
Georg Brandl7e27abb2013-10-27 07:23:53 +0100128 line = self.file.readline(_MAXLINE + 1)
129 if len(line) > _MAXLINE:
130 raise error_proto('line too long')
131
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000132 if self._debugging > 1: print('*get*', repr(line))
Tim Peters2344fae2001-01-15 00:50:52 +0000133 if not line: raise error_proto('-ERR EOF')
134 octets = len(line)
135 # server can send any combination of CR & LF
136 # however, 'readline()' returns lines ending in LF
137 # so only possibilities are ...LF, ...CRLF, CR...LF
138 if line[-2:] == CRLF:
139 return line[:-2], octets
Serhiy Storchaka74a49ac2015-03-20 16:46:19 +0200140 if line[:1] == CR:
Tim Peters2344fae2001-01-15 00:50:52 +0000141 return line[1:-1], octets
142 return line[:-1], octets
Guido van Rossum03774bb1998-04-09 13:50:55 +0000143
Guido van Rossum484772d1998-04-06 18:27:27 +0000144
Tim Peters2344fae2001-01-15 00:50:52 +0000145 # Internal: get a response from the server.
146 # Raise 'error_proto' if the response doesn't start with '+'.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000147
Tim Peters2344fae2001-01-15 00:50:52 +0000148 def _getresp(self):
149 resp, o = self._getline()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000150 if self._debugging > 1: print('*resp*', repr(resp))
Christian Heimesd3956292008-11-05 19:48:27 +0000151 if not resp.startswith(b'+'):
Tim Peters2344fae2001-01-15 00:50:52 +0000152 raise error_proto(resp)
153 return resp
Guido van Rossum484772d1998-04-06 18:27:27 +0000154
Guido van Rossum03774bb1998-04-09 13:50:55 +0000155
Tim Peters2344fae2001-01-15 00:50:52 +0000156 # Internal: get a response plus following text from the server.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000157
Tim Peters2344fae2001-01-15 00:50:52 +0000158 def _getlongresp(self):
159 resp = self._getresp()
160 list = []; octets = 0
161 line, o = self._getline()
Guido van Rossum0ec34772007-09-10 00:27:13 +0000162 while line != b'.':
Christian Heimesd3956292008-11-05 19:48:27 +0000163 if line.startswith(b'..'):
Tim Peters2344fae2001-01-15 00:50:52 +0000164 o = o-1
165 line = line[1:]
166 octets = octets + o
167 list.append(line)
168 line, o = self._getline()
169 return resp, list, octets
Guido van Rossum03774bb1998-04-09 13:50:55 +0000170
Guido van Rossum484772d1998-04-06 18:27:27 +0000171
Tim Peters2344fae2001-01-15 00:50:52 +0000172 # Internal: send a command and get the response
Guido van Rossum03774bb1998-04-09 13:50:55 +0000173
Tim Peters2344fae2001-01-15 00:50:52 +0000174 def _shortcmd(self, line):
175 self._putcmd(line)
176 return self._getresp()
Guido van Rossum484772d1998-04-06 18:27:27 +0000177
Guido van Rossum03774bb1998-04-09 13:50:55 +0000178
Tim Peters2344fae2001-01-15 00:50:52 +0000179 # Internal: send a command and get the response plus following text
Guido van Rossum03774bb1998-04-09 13:50:55 +0000180
Tim Peters2344fae2001-01-15 00:50:52 +0000181 def _longcmd(self, line):
182 self._putcmd(line)
183 return self._getlongresp()
Guido van Rossum484772d1998-04-06 18:27:27 +0000184
Guido van Rossum03774bb1998-04-09 13:50:55 +0000185
Tim Peters2344fae2001-01-15 00:50:52 +0000186 # These can be useful:
187
188 def getwelcome(self):
189 return self.welcome
190
191
192 def set_debuglevel(self, level):
193 self._debugging = level
194
195
196 # Here are all the POP commands:
197
198 def user(self, user):
199 """Send user name, return response
Guido van Rossum484772d1998-04-06 18:27:27 +0000200
Tim Peters2344fae2001-01-15 00:50:52 +0000201 (should indicate password required).
202 """
203 return self._shortcmd('USER %s' % user)
Guido van Rossum484772d1998-04-06 18:27:27 +0000204
Guido van Rossum03774bb1998-04-09 13:50:55 +0000205
Tim Peters2344fae2001-01-15 00:50:52 +0000206 def pass_(self, pswd):
207 """Send password, return response
Guido van Rossum484772d1998-04-06 18:27:27 +0000208
Tim Peters2344fae2001-01-15 00:50:52 +0000209 (response includes message count, mailbox size).
Guido van Rossum03774bb1998-04-09 13:50:55 +0000210
Tim Peters2344fae2001-01-15 00:50:52 +0000211 NB: mailbox is locked by server from here to 'quit()'
212 """
213 return self._shortcmd('PASS %s' % pswd)
Guido van Rossum484772d1998-04-06 18:27:27 +0000214
Guido van Rossum03774bb1998-04-09 13:50:55 +0000215
Tim Peters2344fae2001-01-15 00:50:52 +0000216 def stat(self):
217 """Get mailbox status.
Guido van Rossum484772d1998-04-06 18:27:27 +0000218
Tim Peters2344fae2001-01-15 00:50:52 +0000219 Result is tuple of 2 ints (message count, mailbox size)
220 """
221 retval = self._shortcmd('STAT')
Eric S. Raymond341f9292001-02-09 06:56:56 +0000222 rets = retval.split()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000223 if self._debugging: print('*stat*', repr(rets))
Eric S. Raymond341f9292001-02-09 06:56:56 +0000224 numMessages = int(rets[1])
225 sizeMessages = int(rets[2])
Tim Peters2344fae2001-01-15 00:50:52 +0000226 return (numMessages, sizeMessages)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000227
Guido van Rossum03774bb1998-04-09 13:50:55 +0000228
Tim Peters2344fae2001-01-15 00:50:52 +0000229 def list(self, which=None):
230 """Request listing, return result.
Guido van Rossum484772d1998-04-06 18:27:27 +0000231
Tim Peters2344fae2001-01-15 00:50:52 +0000232 Result without a message number argument is in form
Georg Brandl2772c672005-08-05 21:01:58 +0000233 ['response', ['mesg_num octets', ...], octets].
Guido van Rossum484772d1998-04-06 18:27:27 +0000234
Tim Peters2344fae2001-01-15 00:50:52 +0000235 Result when a message number argument is given is a
236 single response: the "scan listing" for that message.
237 """
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000238 if which is not None:
Tim Peters2344fae2001-01-15 00:50:52 +0000239 return self._shortcmd('LIST %s' % which)
240 return self._longcmd('LIST')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000241
Guido van Rossum03774bb1998-04-09 13:50:55 +0000242
Tim Peters2344fae2001-01-15 00:50:52 +0000243 def retr(self, which):
244 """Retrieve whole message number 'which'.
Guido van Rossumf6ae7431998-09-02 14:42:02 +0000245
Tim Peters2344fae2001-01-15 00:50:52 +0000246 Result is in form ['response', ['line', ...], octets].
247 """
248 return self._longcmd('RETR %s' % which)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000249
Guido van Rossum484772d1998-04-06 18:27:27 +0000250
Tim Peters2344fae2001-01-15 00:50:52 +0000251 def dele(self, which):
252 """Delete message number 'which'.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000253
Tim Peters2344fae2001-01-15 00:50:52 +0000254 Result is 'response'.
255 """
256 return self._shortcmd('DELE %s' % which)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000257
Guido van Rossum484772d1998-04-06 18:27:27 +0000258
Tim Peters2344fae2001-01-15 00:50:52 +0000259 def noop(self):
260 """Does nothing.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000261
Tim Peters2344fae2001-01-15 00:50:52 +0000262 One supposes the response indicates the server is alive.
263 """
264 return self._shortcmd('NOOP')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000265
Guido van Rossum484772d1998-04-06 18:27:27 +0000266
Tim Peters2344fae2001-01-15 00:50:52 +0000267 def rset(self):
Benjamin Petersona37cfc62008-05-26 13:48:34 +0000268 """Unmark all messages marked for deletion."""
Tim Peters2344fae2001-01-15 00:50:52 +0000269 return self._shortcmd('RSET')
Guido van Rossum484772d1998-04-06 18:27:27 +0000270
Guido van Rossum03774bb1998-04-09 13:50:55 +0000271
Tim Peters2344fae2001-01-15 00:50:52 +0000272 def quit(self):
273 """Signoff: commit changes on server, unlock mailbox, close connection."""
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000274 resp = self._shortcmd('QUIT')
275 self.close()
Tim Peters2344fae2001-01-15 00:50:52 +0000276 return resp
Guido van Rossum484772d1998-04-06 18:27:27 +0000277
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000278 def close(self):
279 """Close the connection without assuming anything about it."""
Serhiy Storchaka7e7a3db2015-04-10 13:24:41 +0300280 try:
281 file = self.file
282 self.file = None
283 if file is not None:
284 file.close()
285 finally:
286 sock = self.sock
287 self.sock = None
288 if sock is not None:
289 try:
290 sock.shutdown(socket.SHUT_RDWR)
Victor Stinner83a2c282017-05-15 17:33:45 +0200291 except OSError as exc:
292 # The server might already have closed the connection.
293 # On Windows, this may result in WSAEINVAL (error 10022):
294 # An invalid operation was attempted.
295 if (exc.errno != errno.ENOTCONN
296 and getattr(exc, 'winerror', 0) != 10022):
Serhiy Storchaka7e7a3db2015-04-10 13:24:41 +0300297 raise
298 finally:
299 sock.close()
Giampaolo Rodolà95bcb932011-02-25 22:28:24 +0000300
Tim Peters2344fae2001-01-15 00:50:52 +0000301 #__del__ = quit
Guido van Rossum484772d1998-04-06 18:27:27 +0000302
Guido van Rossum484772d1998-04-06 18:27:27 +0000303
Tim Peters2344fae2001-01-15 00:50:52 +0000304 # optional commands:
Guido van Rossum03774bb1998-04-09 13:50:55 +0000305
Tim Peters2344fae2001-01-15 00:50:52 +0000306 def rpop(self, user):
307 """Not sure what this does."""
308 return self._shortcmd('RPOP %s' % user)
Guido van Rossum03774bb1998-04-09 13:50:55 +0000309
Guido van Rossum03774bb1998-04-09 13:50:55 +0000310
Christian Heimesd3956292008-11-05 19:48:27 +0000311 timestamp = re.compile(br'\+OK.*(<[^>]+>)')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000312
Christian Heimesd3956292008-11-05 19:48:27 +0000313 def apop(self, user, password):
Tim Peters2344fae2001-01-15 00:50:52 +0000314 """Authorisation
Guido van Rossum03774bb1998-04-09 13:50:55 +0000315
Tim Peters2344fae2001-01-15 00:50:52 +0000316 - only possible if server has supplied a timestamp in initial greeting.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000317
Tim Peters2344fae2001-01-15 00:50:52 +0000318 Args:
Christian Heimesd3956292008-11-05 19:48:27 +0000319 user - mailbox user;
320 password - mailbox password.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000321
Tim Peters2344fae2001-01-15 00:50:52 +0000322 NB: mailbox is locked by server from here to 'quit()'
323 """
Mark Dickinsonea1158f2009-08-06 16:06:25 +0000324 secret = bytes(password, self.encoding)
Moshe Zadkaccc2e3d2001-01-19 19:56:27 +0000325 m = self.timestamp.match(self.welcome)
326 if not m:
Tim Peters2344fae2001-01-15 00:50:52 +0000327 raise error_proto('-ERR APOP not supported by server')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000328 import hashlib
Christian Heimesd3956292008-11-05 19:48:27 +0000329 digest = m.group(1)+secret
330 digest = hashlib.md5(digest).hexdigest()
Tim Peters2344fae2001-01-15 00:50:52 +0000331 return self._shortcmd('APOP %s %s' % (user, digest))
Guido van Rossum03774bb1998-04-09 13:50:55 +0000332
Guido van Rossum03774bb1998-04-09 13:50:55 +0000333
Tim Peters2344fae2001-01-15 00:50:52 +0000334 def top(self, which, howmuch):
335 """Retrieve message header of message number 'which'
336 and first 'howmuch' lines of message body.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000337
Tim Peters2344fae2001-01-15 00:50:52 +0000338 Result is in form ['response', ['line', ...], octets].
339 """
340 return self._longcmd('TOP %s %s' % (which, howmuch))
Guido van Rossum03774bb1998-04-09 13:50:55 +0000341
Guido van Rossum03774bb1998-04-09 13:50:55 +0000342
Tim Peters2344fae2001-01-15 00:50:52 +0000343 def uidl(self, which=None):
344 """Return message digest (unique id) list.
Guido van Rossum03774bb1998-04-09 13:50:55 +0000345
Tim Peters2344fae2001-01-15 00:50:52 +0000346 If 'which', result contains unique id for that message
347 in the form 'response mesgnum uid', otherwise result is
348 the list ['response', ['mesgnum uid', ...], octets]
349 """
Raymond Hettinger16e3c422002-06-01 16:07:16 +0000350 if which is not None:
Tim Peters2344fae2001-01-15 00:50:52 +0000351 return self._shortcmd('UIDL %s' % which)
352 return self._longcmd('UIDL')
Guido van Rossum03774bb1998-04-09 13:50:55 +0000353
Antoine Pitrou25cee192012-11-23 20:07:39 +0100354
R David Murrayb8cd3e42015-05-16 15:05:53 -0400355 def utf8(self):
356 """Try to enter UTF-8 mode (see RFC 6856). Returns server response.
357 """
358 return self._shortcmd('UTF8')
359
360
Antoine Pitrou25cee192012-11-23 20:07:39 +0100361 def capa(self):
362 """Return server capabilities (RFC 2449) as a dictionary
363 >>> c=poplib.POP3('localhost')
364 >>> c.capa()
365 {'IMPLEMENTATION': ['Cyrus', 'POP3', 'server', 'v2.2.12'],
366 'TOP': [], 'LOGIN-DELAY': ['0'], 'AUTH-RESP-CODE': [],
367 'EXPIRE': ['NEVER'], 'USER': [], 'STLS': [], 'PIPELINING': [],
368 'UIDL': [], 'RESP-CODES': []}
369 >>>
370
371 Really, according to RFC 2449, the cyrus folks should avoid
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300372 having the implementation split into multiple arguments...
Antoine Pitrou25cee192012-11-23 20:07:39 +0100373 """
374 def _parsecap(line):
375 lst = line.decode('ascii').split()
376 return lst[0], lst[1:]
377
378 caps = {}
379 try:
380 resp = self._longcmd('CAPA')
381 rawcaps = resp[1]
382 for capline in rawcaps:
383 capnm, capargs = _parsecap(capline)
384 caps[capnm] = capargs
385 except error_proto as _err:
386 raise error_proto('-ERR CAPA not supported by server')
387 return caps
388
Antoine Pitrou8618d742012-11-23 20:13:48 +0100389
390 def stls(self, context=None):
391 """Start a TLS session on the active connection as specified in RFC 2595.
392
393 context - a ssl.SSLContext
394 """
395 if not HAVE_SSL:
396 raise error_proto('-ERR TLS support missing')
397 if self._tls_established:
398 raise error_proto('-ERR TLS session already established')
399 caps = self.capa()
400 if not 'STLS' in caps:
401 raise error_proto('-ERR STLS not supported by server')
402 if context is None:
Christian Heimes67986f92013-11-23 22:43:47 +0100403 context = ssl._create_stdlib_context()
Antoine Pitrou8618d742012-11-23 20:13:48 +0100404 resp = self._shortcmd('STLS')
Christian Heimes1bc70682013-12-02 20:10:50 +0100405 self.sock = context.wrap_socket(self.sock,
Benjamin Peterson7243b572014-11-23 17:04:34 -0600406 server_hostname=self.host)
Antoine Pitrou8618d742012-11-23 20:13:48 +0100407 self.file = self.sock.makefile('rb')
408 self._tls_established = True
409 return resp
410
411
412if HAVE_SSL:
Martin v. Löwis48440b72003-10-31 12:52:35 +0000413
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000414 class POP3_SSL(POP3):
415 """POP3 client class over SSL connection
Martin v. Löwis48440b72003-10-31 12:52:35 +0000416
Antoine Pitrou8618d742012-11-23 20:13:48 +0100417 Instantiate with: POP3_SSL(hostname, port=995, keyfile=None, certfile=None,
418 context=None)
Martin v. Löwis48440b72003-10-31 12:52:35 +0000419
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000420 hostname - the hostname of the pop3 over ssl server
421 port - port number
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300422 keyfile - PEM formatted file that contains your private key
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000423 certfile - PEM formatted certificate chain file
Antoine Pitrou8618d742012-11-23 20:13:48 +0100424 context - a ssl.SSLContext
Martin v. Löwis48440b72003-10-31 12:52:35 +0000425
Christian Heimesd3956292008-11-05 19:48:27 +0000426 See the methods of the parent class POP3 for more documentation.
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000427 """
Martin v. Löwis48440b72003-10-31 12:52:35 +0000428
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000429 def __init__(self, host, port=POP3_SSL_PORT, keyfile=None, certfile=None,
430 timeout=socket._GLOBAL_DEFAULT_TIMEOUT, context=None):
431 if context is not None and keyfile is not None:
432 raise ValueError("context and keyfile arguments are mutually "
433 "exclusive")
434 if context is not None and certfile is not None:
435 raise ValueError("context and certfile arguments are mutually "
436 "exclusive")
Christian Heimesd0486372016-09-10 23:23:33 +0200437 if keyfile is not None or certfile is not None:
438 import warnings
439 warnings.warn("keyfile and certfile are deprecated, use a"
440 "custom context instead", DeprecationWarning, 2)
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000441 self.keyfile = keyfile
442 self.certfile = certfile
Christian Heimes67986f92013-11-23 22:43:47 +0100443 if context is None:
444 context = ssl._create_stdlib_context(certfile=certfile,
445 keyfile=keyfile)
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000446 self.context = context
Christian Heimesd3956292008-11-05 19:48:27 +0000447 POP3.__init__(self, host, port, timeout)
Martin v. Löwis48440b72003-10-31 12:52:35 +0000448
Christian Heimesd3956292008-11-05 19:48:27 +0000449 def _create_socket(self, timeout):
450 sock = POP3._create_socket(self, timeout)
Christian Heimes1bc70682013-12-02 20:10:50 +0100451 sock = self.context.wrap_socket(sock,
Benjamin Peterson7243b572014-11-23 17:04:34 -0600452 server_hostname=self.host)
Giampaolo Rodolà42382fe2010-08-17 16:09:53 +0000453 return sock
Martin v. Löwis48440b72003-10-31 12:52:35 +0000454
Antoine Pitrou8618d742012-11-23 20:13:48 +0100455 def stls(self, keyfile=None, certfile=None, context=None):
456 """The method unconditionally raises an exception since the
457 STLS command doesn't make any sense on an already established
458 SSL/TLS session.
459 """
460 raise error_proto('-ERR TLS session already established')
461
Thomas Wouters47b49bf2007-08-30 22:15:33 +0000462 __all__.append("POP3_SSL")
Guido van Rossum03774bb1998-04-09 13:50:55 +0000463
Guido van Rossum484772d1998-04-06 18:27:27 +0000464if __name__ == "__main__":
Eric S. Raymond341f9292001-02-09 06:56:56 +0000465 import sys
466 a = POP3(sys.argv[1])
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000467 print(a.getwelcome())
Eric S. Raymond341f9292001-02-09 06:56:56 +0000468 a.user(sys.argv[2])
469 a.pass_(sys.argv[3])
Tim Peters2344fae2001-01-15 00:50:52 +0000470 a.list()
471 (numMsgs, totalSize) = a.stat()
472 for i in range(1, numMsgs + 1):
473 (header, msg, octets) = a.retr(i)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000474 print("Message %d:" % i)
Tim Peters2344fae2001-01-15 00:50:52 +0000475 for line in msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000476 print(' ' + line)
477 print('-----------------------')
Tim Peters2344fae2001-01-15 00:50:52 +0000478 a.quit()