or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-extensions.mdhttp-client.mdindex.mdoauth-core.mdserver-verification.md

client-extensions.mddocs/

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.