Skip to content

Instantly share code, notes, and snippets.

@chaserhkj
Last active October 21, 2023 07:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chaserhkj/8e1a61ce8b03cd4a417f72d2cba22b35 to your computer and use it in GitHub Desktop.
Save chaserhkj/8e1a61ce8b03cd4a417f72d2cba22b35 to your computer and use it in GitHub Desktop.
Patch for ssmtp to support safer XOAuth2 authentication (see comment for details)
Adds XOAUTH2 functionality for safer authentication.
Still needs a separate script/service to obtain and refresh OAUTH2
access token for most mail providers.
Patch by Moriyoshi Koizumi <mozo@mozo.jp>
Modified by Kangjing Huang <huangkangjing@gmail.com>
diff --color -u ssmtp-2.64.orig/ssmtp.c ssmtp-2.64/ssmtp.c
--- ssmtp-2.64.orig/ssmtp.c 2023-10-21 00:39:18.895976193 -0400
+++ ssmtp-2.64/ssmtp.c 2023-10-21 00:40:59.993918590 -0400
@@ -1604,6 +1604,7 @@
}
else {
#endif
+ if(auth_method && strcasecmp(auth_method, "login") == 0) {
memset(buf, 0, bufsize);
to64frombits(buf, auth_user, strlen(auth_user));
if (use_oldauth) {
@@ -1628,6 +1629,22 @@
memset(buf, 0, bufsize);
to64frombits(buf, auth_pass, strlen(auth_pass));
+ } else if(auth_method && strcasecmp(auth_method, "xoauth2") == 0) {
+ int authbuflen;
+ char *authbuf = malloc(5 + strlen(auth_user) + 1 + 5 + 6 + 1 + strlen(auth_pass) + 2 + 1);
+ if(!authbuf) {
+ die("Out of memory");
+ }
+ outbytes += smtp_write(sock, "AUTH XOAUTH2");
+ alarm((unsigned) MEDWAIT);
+ if(smtp_read(sock, buf) != 3) {
+ die("Server didn't accept AUTH XOAUTH2");
+ }
+ memset(buf, 0, bufsize);
+ authbuflen = sprintf(authbuf, "user=%s\1auth=Bearer %s\1\1", auth_user, auth_pass);
+ to64frombits(buf, (unsigned char*)authbuf, authbuflen);
+ free(authbuf);
+ }
#ifdef MD5AUTH
}
#endif
@chaserhkj
Copy link
Author

chaserhkj commented Oct 21, 2023

To use, put AuthMethod=XOAUTH2 and AuthPass=<your obtained OAuth2 access token> in /etc/ssmtp/ssmtp.conf and you should be good to go.

Remember that your OAuth2 access token is often short-lived and will expire in small intervals. (for example, GMail access token only has 1 hour of valid time) You will need at least one script to refresh it using a long-term refresh token.

For GMail, oauth2l (github, aur) can be used to obtain and refresh the access token using your own registered client secret with google. and I use this script:

#!/bin/bash
ACCESS_TOKEN=$(oauth2l fetch --scope=https://mail.google.com/ \
    --credentials=/etc/oauth2l.json --cache=/etc/ssmtp/oauth2l.cache --refresh)
sed -i "s/^AuthPass=.*$/AuthPass=$ACCESS_TOKEN/" /etc/ssmtp/ssmtp.conf

to refresh the access token every time before I send an email from the command line.

  • /etc/oauth2l.json is your client ID info
  • /etc/ssmtp/oauth2l.cache is oauth2l cache location for storing the refresh token.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment