0
# Client Extensions
1
2
Protocol-specific OAuth clients for SMTP and IMAP that provide XOAUTH authentication support. These extensions allow OAuth-authenticated access to email services that support the XOAUTH SASL mechanism.
3
4
## Capabilities
5
6
### IMAP OAuth Client
7
8
OAuth-enabled IMAP client that extends Python's standard imaplib.IMAP4_SSL to support XOAUTH authentication for accessing IMAP email servers with OAuth credentials.
9
10
```python { .api }
11
from oauth2.clients.imap import IMAP4_SSL
12
13
class IMAP4_SSL:
14
def authenticate(self, url: str, consumer, token):
15
"""
16
Authenticate IMAP connection using XOAUTH.
17
18
Args:
19
url (str): IMAP service URL for XOAUTH string generation
20
consumer: OAuth consumer credentials
21
token: OAuth token credentials
22
23
Raises:
24
ValueError: If consumer or token is invalid
25
"""
26
```
27
28
### SMTP OAuth Client
29
30
OAuth-enabled SMTP client that extends Python's standard smtplib.SMTP to support XOAUTH authentication for sending email through OAuth-protected SMTP servers.
31
32
```python { .api }
33
from oauth2.clients.smtp import SMTP
34
35
class SMTP:
36
def authenticate(self, url: str, consumer, token):
37
"""
38
Authenticate SMTP connection using XOAUTH.
39
40
Args:
41
url (str): SMTP service URL for XOAUTH string generation
42
consumer: OAuth consumer credentials
43
token: OAuth token credentials
44
45
Raises:
46
ValueError: If consumer or token is invalid
47
"""
48
```
49
50
## Usage Examples
51
52
### Gmail IMAP Access
53
54
```python
55
import oauth2
56
from oauth2.clients.imap import IMAP4_SSL
57
58
# OAuth credentials (obtain through Google OAuth flow)
59
consumer = oauth2.Consumer('your_consumer_key', 'your_consumer_secret')
60
token = oauth2.Token('user_access_token', 'user_access_token_secret')
61
62
# Connect to Gmail IMAP
63
imap_client = IMAP4_SSL('imap.gmail.com', 993)
64
65
# Authenticate using XOAUTH
66
gmail_url = 'https://mail.google.com/mail/b/user@gmail.com/imap/'
67
imap_client.authenticate(gmail_url, consumer, token)
68
69
# Use standard IMAP commands
70
imap_client.select('INBOX')
71
typ, data = imap_client.search(None, 'ALL')
72
73
# Get message IDs
74
message_ids = data[0].split()
75
print(f"Found {len(message_ids)} messages")
76
77
# Fetch first message
78
if message_ids:
79
typ, msg_data = imap_client.fetch(message_ids[0], '(RFC822)')
80
email_body = msg_data[0][1]
81
print(f"First message: {email_body[:200]}...")
82
83
# Close connection
84
imap_client.close()
85
imap_client.logout()
86
```
87
88
### Yahoo Mail IMAP Access
89
90
```python
91
import oauth2
92
from oauth2.clients.imap import IMAP4_SSL
93
94
# Yahoo OAuth credentials
95
consumer = oauth2.Consumer('yahoo_consumer_key', 'yahoo_consumer_secret')
96
token = oauth2.Token('yahoo_access_token', 'yahoo_access_token_secret')
97
98
# Connect to Yahoo IMAP
99
imap_client = IMAP4_SSL('imap.mail.yahoo.com', 993)
100
101
# Authenticate with Yahoo IMAP
102
yahoo_url = 'https://mail.yahoo.com/ws/mail/v1.1/soap'
103
imap_client.authenticate(yahoo_url, consumer, token)
104
105
# List available folders
106
typ, folders = imap_client.list()
107
for folder in folders:
108
print(f"Folder: {folder}")
109
110
# Select inbox and get message count
111
imap_client.select('INBOX')
112
typ, data = imap_client.search(None, 'UNSEEN')
113
unseen_count = len(data[0].split()) if data[0] else 0
114
print(f"Unseen messages: {unseen_count}")
115
116
imap_client.logout()
117
```
118
119
### Gmail SMTP Sending
120
121
```python
122
import oauth2
123
from oauth2.clients.smtp import SMTP
124
from email.mime.text import MIMEText
125
from email.mime.multipart import MIMEMultipart
126
127
# OAuth credentials
128
consumer = oauth2.Consumer('gmail_consumer_key', 'gmail_consumer_secret')
129
token = oauth2.Token('user_access_token', 'user_access_token_secret')
130
131
# Connect to Gmail SMTP
132
smtp_client = SMTP('smtp.gmail.com', 587)
133
smtp_client.starttls()
134
135
# Authenticate using XOAUTH
136
gmail_url = 'https://mail.google.com/mail/b/user@gmail.com/smtp/'
137
smtp_client.authenticate(gmail_url, consumer, token)
138
139
# Create message
140
msg = MIMEMultipart()
141
msg['From'] = 'user@gmail.com'
142
msg['To'] = 'recipient@example.com'
143
msg['Subject'] = 'OAuth Test Email'
144
145
body = 'This email was sent using OAuth authentication!'
146
msg.attach(MIMEText(body, 'plain'))
147
148
# Send message
149
text = msg.as_string()
150
smtp_client.sendmail('user@gmail.com', 'recipient@example.com', text)
151
152
# Close connection
153
smtp_client.quit()
154
```
155
156
### Error Handling
157
158
```python
159
import oauth2
160
from oauth2.clients.imap import IMAP4_SSL
161
import imaplib
162
import socket
163
164
consumer = oauth2.Consumer('consumer_key', 'consumer_secret')
165
token = oauth2.Token('token_key', 'token_secret')
166
167
try:
168
# Connect to IMAP server
169
imap_client = IMAP4_SSL('imap.gmail.com', 993)
170
171
# Authenticate
172
gmail_url = 'https://mail.google.com/mail/b/user@gmail.com/imap/'
173
imap_client.authenticate(gmail_url, consumer, token)
174
175
print("Authentication successful!")
176
177
except ValueError as e:
178
print(f"Invalid credentials: {e}")
179
180
except imaplib.IMAP4.abort as e:
181
print(f"IMAP connection aborted: {e}")
182
183
except imaplib.IMAP4.error as e:
184
print(f"IMAP error: {e}")
185
# Common errors:
186
# - Invalid credentials
187
# - Authentication failure
188
# - Server rejected XOAUTH
189
190
except socket.error as e:
191
print(f"Network error: {e}")
192
193
except Exception as e:
194
print(f"Unexpected error: {e}")
195
196
finally:
197
try:
198
imap_client.logout()
199
except:
200
pass
201
```
202
203
### Advanced IMAP Operations
204
205
```python
206
import oauth2
207
from oauth2.clients.imap import IMAP4_SSL
208
import email
209
from datetime import datetime, timedelta
210
211
consumer = oauth2.Consumer('consumer_key', 'consumer_secret')
212
token = oauth2.Token('token_key', 'token_secret')
213
214
imap_client = IMAP4_SSL('imap.gmail.com', 993)
215
gmail_url = 'https://mail.google.com/mail/b/user@gmail.com/imap/'
216
imap_client.authenticate(gmail_url, consumer, token)
217
218
# Select inbox
219
imap_client.select('INBOX')
220
221
# Search for messages from last week
222
week_ago = (datetime.now() - timedelta(days=7)).strftime('%d-%b-%Y')
223
typ, data = imap_client.search(None, f'SINCE {week_ago}')
224
225
message_ids = data[0].split()
226
print(f"Found {len(message_ids)} messages from last week")
227
228
# Process each message
229
for msg_id in message_ids[:5]: # Process first 5 messages
230
typ, msg_data = imap_client.fetch(msg_id, '(RFC822)')
231
232
# Parse email
233
email_message = email.message_from_bytes(msg_data[0][1])
234
235
print(f"From: {email_message['From']}")
236
print(f"Subject: {email_message['Subject']}")
237
print(f"Date: {email_message['Date']}")
238
239
# Get email body
240
if email_message.is_multipart():
241
for part in email_message.walk():
242
if part.get_content_type() == "text/plain":
243
body = part.get_payload(decode=True).decode('utf-8')
244
print(f"Body preview: {body[:100]}...")
245
break
246
else:
247
body = email_message.get_payload(decode=True).decode('utf-8')
248
print(f"Body preview: {body[:100]}...")
249
250
print("-" * 50)
251
252
imap_client.close()
253
imap_client.logout()
254
```
255
256
### Bulk Email Processing
257
258
```python
259
import oauth2
260
from oauth2.clients.smtp import SMTP
261
from email.mime.text import MIMEText
262
import time
263
264
consumer = oauth2.Consumer('consumer_key', 'consumer_secret')
265
token = oauth2.Token('token_key', 'token_secret')
266
267
# Connect once for multiple sends
268
smtp_client = SMTP('smtp.gmail.com', 587)
269
smtp_client.starttls()
270
271
gmail_url = 'https://mail.google.com/mail/b/user@gmail.com/smtp/'
272
smtp_client.authenticate(gmail_url, consumer, token)
273
274
# Send multiple emails
275
recipients = ['user1@example.com', 'user2@example.com', 'user3@example.com']
276
277
for recipient in recipients:
278
msg = MIMEText(f'Hello {recipient}! This is a personalized message.')
279
msg['From'] = 'sender@gmail.com'
280
msg['To'] = recipient
281
msg['Subject'] = 'Bulk Email Test'
282
283
try:
284
smtp_client.sendmail('sender@gmail.com', recipient, msg.as_string())
285
print(f"Email sent to {recipient}")
286
287
# Rate limiting
288
time.sleep(1)
289
290
except Exception as e:
291
print(f"Failed to send to {recipient}: {e}")
292
293
smtp_client.quit()
294
```
295
296
## Service-Specific Notes
297
298
### Google Services
299
300
- **IMAP URL**: `https://mail.google.com/mail/b/{email}/imap/`
301
- **SMTP URL**: `https://mail.google.com/mail/b/{email}/smtp/`
302
- **Requirements**: Enable "Less secure app access" or use App Passwords
303
- **Scopes**: Requires appropriate Gmail API scopes during OAuth flow
304
305
### Yahoo Mail
306
307
- **IMAP URL**: `https://mail.yahoo.com/ws/mail/v1.1/soap`
308
- **SMTP URL**: `https://mail.yahoo.com/`
309
- **Port**: IMAP 993 (SSL), SMTP 587 (TLS)
310
- **Requirements**: Yahoo OAuth app registration required
311
312
### Generic OAuth Email Providers
313
314
The XOAUTH mechanism works with any email provider that supports it. Check provider documentation for:
315
- XOAUTH support status
316
- Required URL format for authentication
317
- OAuth scope requirements
318
- Server endpoints and ports
319
320
## Implementation Details
321
322
### XOAUTH String Format
323
324
The clients use `oauth2.build_xoauth_string()` to generate XOAUTH authentication strings in the format:
325
326
```
327
GET {url} oauth_consumer_key="{key}",oauth_nonce="{nonce}",oauth_signature="{signature}",oauth_signature_method="HMAC-SHA1",oauth_timestamp="{timestamp}",oauth_token="{token}",oauth_version="1.0"
328
```
329
330
### Base64 Encoding
331
332
SMTP client automatically base64-encodes the XOAUTH string as required by the SMTP AUTH command, while IMAP passes the string directly to the IMAP AUTHENTICATE command.