SMTP OAuth Setup Guide
August 23, 2025 · View on GitHub
Table Of Contents
- SMTP OAuth Setup Guide
SMTP OAuth Setup Guide
Introduction
This guide walks you through setting up OAuth authentication for SMTP email sending with various providers, specifically for use with the mailsend-go program. OAuth is becoming the standard for email authentication as providers phase out traditional username/password methods.
mailsend-go only needs XOAUTH2 access token to send email after authenticating with the access token. It does not know anything on how to obtain an access token from an OAuth provider - the process varies provider to provider. This document describes how to obtain an access token from a provider externally to send mail using mailsend-go. Here is how mailsend-go uses an access token to send an email:
mailsend-go -from user@example.com \
-to user@gmail.com \
-subject test \
...
auth -oauth2 -token "access_token"
Obtaining access token is a multi-step process, e.g.
- Obtain client id and client secret from the provider first
- Obtain an Authorization code using client id. Authorization code expires quickly, usually within 10 minutes
- Use Authorization code, client id, client secret to obtain access token and refresh token
- Access token expires fast - Use refresh token to obtain a new access token. Refresh token expires after few days of inactivity. When refresh token is deleted, you've to start all over again from Step 2
Why OAuth?
Email providers are moving away from username/password authentication for security reasons:
- Microsoft has already deprecated basic authentication for Exchange Online/Outlook
- Google is phasing out "less secure app access" and app passwords
- Yahoo and other providers are following suit
What You'll Get
This document helps you obtain access tokens required for SMTP XOAUTH2 authentication with the mailsend-go program. The bottom line is: you must get an access token from the OAuth provider before sending mail using mailsend-go using SMTP XOAUTH2 authentication.
Recommended Tool - oauth-helper
For most users, we recommend using oauth-helper, a command-line tool that automates the entire OAuth process. It eliminates the need for manual curl commands and complex scripts shown in this guide.
Quick oauth-helper usage:
# Get initial tokens (interactive browser flow)
oauth-helper get gmail --credentials-file client_secret.json
# Refresh access token
oauth-helper refresh gmail --refresh-token "your_refresh_token"
# Validate token
oauth-helper validate --token "your_access_token"
Continue reading this guide if you:
- Want to understand the underlying OAuth process
- Need to implement custom OAuth flows
- Prefer manual control over the authentication process
- Are troubleshooting oauth-helper issues
About This Guide
Most OAuth documentation online is outdated or overly complex. This document provides current, step-by-step instructions that actually work with today's provider interfaces.
Important: This document sets up OAuth for testing and development purposes only. The setup process creates test users and keeps your application in "testing" mode. For production use, additional steps like app verification may be required by some providers.
Gmail
Google's OAuth documentation and console interface are notoriously confusing. The UI changes frequently, and most tutorials online are outdated. This section provides current, tested instructions for setting up Gmail OAuth.
Please send a pull request if you find any outdated information.
Flow

Prerequisites
- A Gmail account
- Access to Google Cloud Console
- Recommended: oauth-helper tool
- For manual setup:
curlcommand line tool andjq(optional, for pretty JSON formatting)
Quick Start with oauth-helper
If you want to skip the manual setup and get tokens immediately:
-
Download oauth-helper from releases
-
Set up Google Cloud Console (you still need to do steps 1-5 below to get credentials)
-
Get tokens in one command:
# Interactive flow - opens browser automatically
oauth-helper get gmail --credentials-file client_secret.json
# Or specify credentials directly
oauth-helper get gmail --client-id "your_id" --client-secret "your_secret"
# Get JSON output for scripts
oauth-helper get gmail --credentials-file client_secret.json --output json
- Use with mailsend-go:
mailsend-go -from you@gmail.com -to recipient@example.com \
-subject "Test Email" -use gmail \
auth -user you@gmail.com -oauth2 -token "your_access_token"
Continue reading for detailed Google Cloud Console setup and manual token management.
Manual Setup (Advanced Users)
Step 1: Create Google Cloud Project
- Go to Google Cloud Console
- Click the project dropdown at the top of the page
- Click "NEW PROJECT"
- Enter a project name (e.g.,
mailsend-oauth) - Click "CREATE"
- Wait for the project to be created and make sure it's selected
Step 2: Enable Gmail API
- In Google Cloud Console, click the hamburger menu (≡) in the top left
- Navigate to "APIs & Services" → "Library"
- Search for "Gmail API"
- Click on "Gmail API" from the results
- Click "ENABLE"
- Wait for the API to be enabled
Step 3: Configure OAuth Consent Screen
- Navigate to "APIs & Services" → "OAuth consent screen"
- If prompted, choose "External" user type (for personal Gmail accounts)
- Fill in the required information:
- App name: Your application name (e.g., "My SMTP Client")
- User support email: Your email address
- Developer contact information: Your email address
- Click "SAVE AND CONTINUE"
- Skip the "Scopes" section for now - click "SAVE AND CONTINUE"
- We'll add test users in the next section
Note: The OAuth consent screen UI may show different section names like "Branding", "Audience", etc. depending on when you access it.
Step 4: Add Test Users
Since your app is in "External" mode and not verified, you need to add test users:
- In the OAuth consent screen, look for a section called "Test users" or "Audience"
- Click "+ ADD USERS" or "+ Add users"
- Enter your Gmail address (the one you want to send emails from)
- Click "SAVE"
Note: You must add each Gmail address you want to use for sending as a test user.
Step 5: Create OAuth Client Credentials
- Navigate to "APIs & Services" → "Credentials"
- Click "+ CREATE CREDENTIALS"
- Select "OAuth client ID"
- Choose "Desktop application" as the application type
- Give it a name (e.g., "SMTP OAuth Client")
- Click "CREATE"
- Download the JSON file - this contains your
client_idandclient_secret
Important: Save this JSON file securely. You'll use it with oauth-helper or extract the credentials for manual setup.
Getting Tokens
Using oauth-helper (Recommended)
With your credentials file downloaded from Google Cloud Console:
# Get initial tokens with interactive browser flow
oauth-helper get gmail --credentials-file client_secret.json
# Verbose output to see what's happening
oauth-helper get gmail --credentials-file client_secret.json --verbose
# JSON output for automation
oauth-helper get gmail --credentials-file client_secret.json --output json
# Environment variables format
oauth-helper get gmail --credentials-file client_secret.json --output env
oauth-helper will:
- Open your default browser to Google's authorization page
- Handle the OAuth flow automatically
- Display your tokens in the requested format
- Provide usage examples for mailsend-go
Manual Token Exchange (Advanced)
If you prefer to handle the OAuth flow manually or need to understand the process:
Step 6: Get Authorization Code
Create a script to generate the authorization URL:
#!/bin/bash
# get-auth-url.sh
# Extract client_id from your downloaded JSON file
CLIENT_ID="your_client_id_here"
echo "Visit this URL in your browser:"
echo "https://accounts.google.com/o/oauth2/auth?client_id=${CLIENT_ID}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://mail.google.com/&response_type=code&access_type=offline&prompt=consent"
echo ""
echo "After authorizing, copy the authorization code and run the token exchange script."
- Run the script and visit the displayed URL
- Sign in with your Gmail account
- Grant permissions to your application
- Copy the authorization code displayed in the browser
Step 7: Exchange Authorization Code for Tokens
Create a script to exchange the authorization code for access and refresh tokens:
#!/bin/bash
# get-tokens.sh
# Your OAuth client credentials
CLIENT_ID="your_client_id_here"
CLIENT_SECRET="your_client_secret_here"
echo "Enter the authorization code:"
read AUTH_CODE
echo "Getting tokens..."
curl -s -X POST https://oauth2.googleapis.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "code=$AUTH_CODE" \
-d "grant_type=authorization_code" \
-d "redirect_uri=urn:ietf:wg:oauth:2.0:oob" | jq .
This will return a JSON response with:
{
"access_token": "ya29.a0AfH6SMC...",
"expires_in": 3599,
"refresh_token": "1//04-rN5...",
"scope": "https://mail.google.com/",
"token_type": "Bearer",
"refresh_token_expires_in": 604799
}
Note: Authorization code expires very quickly.
Understanding the Response:
access_token
- What it is: The actual token used to authenticate API calls
- Usage: Include in HTTP headers as Authorization: Bearer <access_token>
- For SMTP: Used by your mailsend-go XOAUTH2 implementation to authenticate with Gmail's SMTP server
expires_in:3599
- What it is: How long the access token is valid (in seconds)
- 3599 seconds = 59 minutes and 59 seconds (almost 1 hour)
- After expiration: You will need a new access token (use refresh token to get one)
refresh_token
- What it is: Long-lived token used to get new access tokens
- Usage: When access token expires, use this with your get-oauth-token program or oauth-helper
- Important: Store this securely - it's your long-term access key
scope: "https://mail.google.com/"
- What it is: What permissions this token grants
- This scope: Allows sending emails via SMTP (not Gmail API)
- Must match: The scope you requested during authorization
token_type: "Bearer"
- What it is: How to use the token in requests
- Bearer: Include as Authorization: Bearer <access_token> in headers
- Standard: Almost always "Bearer" for OAuth2
refresh_token_expires_in: 604799
- What it is: How long the refresh token is valid (in seconds)
- 604799 seconds = 7 days (for testing apps with inactivity)
- After expiration: Need to do the full OAuth flow again (get new authorization code)
Summary
- Now: Both tokens are valid
- In 1 hour: Access token expires → use refresh token to get new access token
- In 7 days: Refresh token expires → need to redo OAuth flow from scratch
Token Management
Refreshing Tokens with oauth-helper
When your access token expires (after ~1 hour), use oauth-helper to get a new one:
# Refresh using refresh token
oauth-helper refresh gmail --refresh-token "your_refresh_token"
# Refresh with credentials file (if you have refresh token stored)
oauth-helper refresh gmail --credentials-file client_secret.json --refresh-token "your_refresh_token"
# JSON output for automation
oauth-helper refresh gmail --refresh-token "your_refresh_token" --output json
# Environment variables format
oauth-helper refresh gmail --refresh-token "your_refresh_token" --output env
Automation Example:
#!/bin/bash
# refresh-and-send.sh
# Get fresh access token
ACCESS_TOKEN=$(oauth-helper refresh gmail -r "$GMAIL_REFRESH_TOKEN" --output json | jq -r '.access_token')
# Send email with fresh token
mailsend-go -from you@gmail.com -to recipient@example.com \
-subject "Automated Email" -use gmail \
auth -user you@gmail.com -oauth2 -token "$ACCESS_TOKEN"
Step 8: Refresh Access Token (When Needed)
Use get-oauth-token
Use standalone get-oauth-token
get-oauth-token -r "refresh_token" -i "client_id" -s "client_secret" -j
Use oauth-helper (Recommended)
oauth-helper refresh gmail --refresh-token "refresh_token" --output json
bash with curl
When your access token expires, use the refresh token to get a new one:
#!/bin/bash
# manual-refresh.sh
CLIENT_ID="your_client_id_here"
CLIENT_SECRET="your_client_secret_here"
REFRESH_TOKEN="your_refresh_token_here"
curl -s -X POST https://oauth2.googleapis.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "refresh_token=$REFRESH_TOKEN" \
-d "grant_type=refresh_token" | jq .
Complete Example Script
Here's a complete script that handles the entire flow:
#!/bin/bash
# Configuration
CLIENT_ID="your_client_id_here"
CLIENT_SECRET="your_client_secret_here"
echo "=== Gmail OAuth Token Generator ==="
echo ""
echo "Step 1: Visit this URL in your browser:"
echo "https://accounts.google.com/o/oauth2/auth?client_id=${CLIENT_ID}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://mail.google.com/&response_type=code&access_type=offline&prompt=consent"
echo ""
echo "Step 2: After authorizing, enter the authorization code:"
read -p "Authorization code: " AUTH_CODE
echo ""
echo "Step 3: Exchanging code for tokens..."
RESPONSE=$(curl -s -X POST https://oauth2.googleapis.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "code=$AUTH_CODE" \
-d "grant_type=authorization_code" \
-d "redirect_uri=urn:ietf:wg:oauth:2.0:oob")
echo "Response:"
echo "$RESPONSE" | jq .
# Extract tokens for easy copying
ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.access_token')
REFRESH_TOKEN=$(echo "$RESPONSE" | jq -r '.refresh_token')
echo ""
echo "=== Tokens ==="
echo "Access Token: $ACCESS_TOKEN"
echo "Refresh Token: $REFRESH_TOKEN"
Using the Tokens
Once you have your tokens, you can use them for SMTP OAuth authentication with Gmail:
With mailsend-go:
# Using access token directly
mailsend-go -from you@gmail.com -to recipient@example.com \
-subject "Test Email" -use gmail \
auth -user you@gmail.com -oauth2 -token "your_access_token"
# Using environment variable (recommended for scripts)
export SMTP_OAUTH_TOKEN="your_access_token"
mailsend-go -from you@gmail.com -to recipient@example.com \
-subject "Test Email" -use gmail \
auth -user you@gmail.com -oauth2
SMTP Settings:
- Server:
smtp.gmail.com:587 - Authentication: OAuth2/XOAUTH2 with your access token
- Username: Your Gmail address
- Password/Token: The access token
Troubleshooting
"Error 400: redirect_uri_mismatch"
- Make sure your OAuth client is configured as "Desktop application"
- Verify you're using
urn:ietf:wg:oauth:2.0:oobas the redirect URI - If using oauth-helper, this is handled automatically
"Access blocked: [app] has not completed the Google verification process"
- Make sure you've added your Gmail address as a test user in the OAuth consent screen
- Check that your app is in "Testing" mode, not "In production"
- Verify you're signing in with the correct Gmail account
"Invalid client"
- Double-check your
client_idandclient_secretfrom the downloaded JSON file - Make sure you're using the correct Google Cloud project
- Verify the credentials file path if using oauth-helper
Can't find "Test users" or "Add users"
- The Google Cloud Console UI changes frequently
- Look for sections named "Audience", "Test users", or similar
- The functionality is there, just possibly in a different location
- Try refreshing the page or switching between sections
oauth-helper specific issues
# Validate your credentials file
oauth-helper get gmail --credentials-file client_secret.json --verbose
# Check token validity
oauth-helper validate --token "your_access_token"
# Test refresh token
oauth-helper refresh gmail --refresh-token "your_refresh_token" --verbose
Security Notes
- Never commit your
client_secretor tokens to version control - Store credentials securely in your application
- The refresh token expires after 7 days of inactivity for testing apps
- Access tokens expire after about 1 hour and need to be refreshed
- Use oauth-helper's JSON output format for automation to avoid exposing tokens in command history
Additional Resources
- oauth-helper GitHub Repository
- mailsend-go GitHub Repository
- Google OAuth 2.0 Documentation
- Gmail API Documentation
- Google Cloud Console
Microsoft
TODO
Microsoft OAuth2 support is planned for oauth-helper. Please send a pull request if you are familiar with the Microsoft OAuth flow for SMTP.
Yahoo
TODO
Yahoo OAuth2 support is planned for oauth-helper. Please send a pull request if you are familiar with the Yahoo OAuth flow for SMTP.
Authors
- Created with assistance from Claude AI 3.7,4 Sonnet, working under my guidance and instructions.
TOC is created by https://github.com/muquit/markdown-toc-go on Aug-23-2025