SMTP OAuth Setup Guide

August 23, 2025 · View on GitHub

Table Of Contents

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.

  1. Obtain client id and client secret from the provider first
  2. Obtain an Authorization code using client id. Authorization code expires quickly, usually within 10 minutes
  3. Use Authorization code, client id, client secret to obtain access token and refresh token
  4. 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.

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

SMTP XOAUTH2 Flow

Prerequisites

  • A Gmail account
  • Access to Google Cloud Console
  • Recommended: oauth-helper tool
  • For manual setup: curl command line tool and jq (optional, for pretty JSON formatting)

Quick Start with oauth-helper

If you want to skip the manual setup and get tokens immediately:

  1. Download oauth-helper from releases

  2. Set up Google Cloud Console (you still need to do steps 1-5 below to get credentials)

  3. 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
  1. 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

  1. Go to Google Cloud Console
  2. Click the project dropdown at the top of the page
  3. Click "NEW PROJECT"
  4. Enter a project name (e.g., mailsend-oauth)
  5. Click "CREATE"
  6. Wait for the project to be created and make sure it's selected

Step 2: Enable Gmail API

  1. In Google Cloud Console, click the hamburger menu (≡) in the top left
  2. Navigate to "APIs & Services""Library"
  3. Search for "Gmail API"
  4. Click on "Gmail API" from the results
  5. Click "ENABLE"
  6. Wait for the API to be enabled
  1. Navigate to "APIs & Services""OAuth consent screen"
  2. If prompted, choose "External" user type (for personal Gmail accounts)
  3. 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
  4. Click "SAVE AND CONTINUE"
  5. Skip the "Scopes" section for now - click "SAVE AND CONTINUE"
  6. 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:

  1. In the OAuth consent screen, look for a section called "Test users" or "Audience"
  2. Click "+ ADD USERS" or "+ Add users"
  3. Enter your Gmail address (the one you want to send emails from)
  4. 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

  1. Navigate to "APIs & Services""Credentials"
  2. Click "+ CREATE CREDENTIALS"
  3. Select "OAuth client ID"
  4. Choose "Desktop application" as the application type
  5. Give it a name (e.g., "SMTP OAuth Client")
  6. Click "CREATE"
  7. Download the JSON file - this contains your client_id and client_secret

Important: Save this JSON file securely. You'll use it with oauth-helper or extract the credentials for manual setup.

Getting Tokens

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:

  1. Open your default browser to Google's authorization page
  2. Handle the OAuth flow automatically
  3. Display your tokens in the requested format
  4. 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."
  1. Run the script and visit the displayed URL
  2. Sign in with your Gmail account
  3. Grant permissions to your application
  4. 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
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:oob as 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_id and client_secret from 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_secret or 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

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


TOC is created by https://github.com/muquit/markdown-toc-go on Aug-23-2025