Skip to content

Commit 51dea96

Browse files
Merge pull request #23 from robstewart57/oauth-authentication
Adds support for OAuth authentication
2 parents a5ea361 + b733d67 commit 51dea96

File tree

4 files changed

+50
-7
lines changed

4 files changed

+50
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ A template is provided:
2020
- Indicate if changes are major, minor, or patch changes.
2121
```
2222

23+
## 0.5.0.0
24+
25+
- Adds support for OAuth authentication with a new function `sendMailWithLoginOAuthSTARTTLS`.
26+
2327
## 0.4.0.2
2428

2529
- Switch to `crypton` because the `cryptonite` package is no longer maintained.

Network/Mail/SMTP.hs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ module Network.Mail.SMTP
1818
, sendMailSTARTTLS'
1919
, sendMailWithLoginSTARTTLS
2020
, sendMailWithLoginSTARTTLS'
21+
, sendMailWithLoginOAuthSTARTTLS
22+
, sendMailWithLoginOAuthSTARTTLS'
2123
, sendMailWithSenderSTARTTLS
2224
, sendMailWithSenderSTARTTLS'
2325
, simpleMail
@@ -260,6 +262,17 @@ sendCommand (SMTPC conn _) (AUTH LOGIN username password) = do
260262
command = "AUTH LOGIN"
261263
(userB64, passB64) = encodeLogin username password
262264

265+
sendCommand (SMTPC conn _) (AUTH LOGIN_OAUTH username token) = do
266+
bsPutCrLf conn command
267+
_ <- parseResponse conn
268+
bsPutCrLf conn tokenB64
269+
(code, msg) <- parseResponse conn
270+
unless (code == 235) $ fail "authentication failed."
271+
return (code, msg)
272+
where
273+
command = "AUTH XOAUTH2"
274+
tokenB64 = encodeLoginOAuth username token
275+
263276
sendCommand (SMTPC conn _) (AUTH at username password) = do
264277
bsPutCrLf conn command
265278
(code, msg) <- parseResponse conn
@@ -364,6 +377,14 @@ sendMailWithLoginTLS host user pass mail = connectSMTPS host >>= sendMailWithLog
364377
sendMailWithLoginTLS' :: HostName -> PortNumber -> UserName -> Password -> Mail -> IO ()
365378
sendMailWithLoginTLS' host port user pass mail = connectSMTPS' host port >>= sendMailWithLoginIntern user pass mail
366379

380+
-- | Connect to an SMTP server, login with OAuth, send a 'Mail', disconnect. Uses STARTTLS with the default port (587).
381+
sendMailWithLoginOAuthSTARTTLS :: HostName -> UserName -> Token -> Mail -> IO ()
382+
sendMailWithLoginOAuthSTARTTLS host user token mail = connectSMTPSTARTTLS host >>= sendMailWithLoginOAuthIntern user token mail
383+
384+
-- | Connect to an SMTP server, login with OAuth, send a 'Mail', disconnect. Uses STARTTLS.
385+
sendMailWithLoginOAuthSTARTTLS' :: HostName -> PortNumber -> UserName -> Token -> Mail -> IO ()
386+
sendMailWithLoginOAuthSTARTTLS' host port user token mail = connectSMTPSTARTTLS' host port >>= sendMailWithLoginOAuthIntern user token mail
387+
367388
-- | Send a 'Mail' with a given sender. Uses SMTPS with its default port (465).
368389
sendMailWithSenderTLS :: ByteString -> HostName -> Mail -> IO ()
369390
sendMailWithSenderTLS sender host mail = connectSMTPS host >>= sendMailWithSenderIntern sender mail
@@ -402,6 +423,12 @@ sendMailWithLoginIntern user pass mail con = do
402423
renderAndSend con mail
403424
closeSMTP con
404425

426+
sendMailWithLoginOAuthIntern :: UserName -> Password -> Mail -> SMTPConnection -> IO ()
427+
sendMailWithLoginOAuthIntern user token mail con = do
428+
_ <- sendCommand con (AUTH LOGIN_OAUTH user token)
429+
renderAndSend con mail
430+
closeSMTP con
431+
405432
sendMailWithSenderIntern :: ByteString -> Mail -> SMTPConnection -> IO ()
406433
sendMailWithSenderIntern sender mail con = do
407434
renderAndSendFrom sender con mail

Network/Mail/SMTP/Auth.hs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
module Network.Mail.SMTP.Auth (
22
UserName,
33
Password,
4+
Token,
45
AuthType(..),
56
encodeLogin,
7+
encodeLoginOAuth,
68
auth,
79
) where
810

@@ -19,19 +21,22 @@ import qualified Data.ByteString.Char8 as B8 (unwords)
1921

2022
type UserName = String
2123
type Password = String
24+
type Token = String
2225

2326
data AuthType
2427
= PLAIN
2528
| LOGIN
29+
| LOGIN_OAUTH
2630
| CRAM_MD5
2731
deriving Eq
2832

2933
instance Show AuthType where
3034
showsPrec d at = showParen (d>app_prec) $ showString $ showMain at
3135
where app_prec = 10
32-
showMain PLAIN = "PLAIN"
33-
showMain LOGIN = "LOGIN"
34-
showMain CRAM_MD5 = "CRAM-MD5"
36+
showMain PLAIN = "PLAIN"
37+
showMain LOGIN = "LOGIN"
38+
showMain LOGIN_OAUTH = "XOAUTH2"
39+
showMain CRAM_MD5 = "CRAM-MD5"
3540

3641
toAscii :: String -> ByteString
3742
toAscii = B.pack . map (toEnum.fromEnum)
@@ -50,6 +55,12 @@ encodePlain user pass = b64Encode $ intercalate "\0" [user, user, pass]
5055
encodeLogin :: UserName -> Password -> (ByteString, ByteString)
5156
encodeLogin user pass = (b64Encode user, b64Encode pass)
5257

58+
-- | Encode the xoauth 2 message based on:
59+
-- https://docs.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#sasl-xoauth2
60+
encodeLoginOAuth :: UserName -> Token -> ByteString
61+
encodeLoginOAuth user oauthToken =
62+
b64Encode ("user=" <> user <> "\x01" <> "auth=Bearer " <> oauthToken <> "\x01\x01")
63+
5364
cramMD5 :: String -> UserName -> Password -> ByteString
5465
cramMD5 challenge user pass =
5566
B64.encode $ B8.unwords [user', B16.encode (hmacMD5 challenge' pass')]
@@ -59,6 +70,7 @@ cramMD5 challenge user pass =
5970
pass' = toAscii pass
6071

6172
auth :: AuthType -> String -> UserName -> Password -> ByteString
62-
auth PLAIN _ u p = encodePlain u p
63-
auth LOGIN _ u p = let (u', p') = encodeLogin u p in B8.unwords [u', p']
64-
auth CRAM_MD5 c u p = cramMD5 c u p
73+
auth PLAIN _ u p = encodePlain u p
74+
auth LOGIN _ u p = let (u', p') = encodeLogin u p in B8.unwords [u', p']
75+
auth LOGIN_OAUTH _ u t = encodeLoginOAuth u t
76+
auth CRAM_MD5 c u p = cramMD5 c u p

smtp-mail.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: smtp-mail
2-
version: 0.4.0.2
2+
version: 0.5.0.0
33
synopsis: Simple email sending via SMTP
44
description: This packages provides a simple interface for mail over SMTP. Please see the README for more information.
55
homepage: http://github.com/haskell-github-trust/smtp-mail

0 commit comments

Comments
 (0)