You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Golang调用Gmail API实现跨账号邮件发送

Golang 调用 Gmail API 实现个人账号发信可行方案

前置准备

  • 进入Google Cloud控制台创建新项目,在API库中搜索启用Gmail API
  • 创建OAuth 2.0客户端凭证,应用类型选择「桌面应用」,下载生成的凭证文件保存为credentials.json放到项目目录
  • 权限范围仅申请https://www.googleapis.com/auth/gmail.send即可,该权限仅允许发信,不会触发高权限的安全审核,个人使用可以直接通过

依赖安装

执行命令安装官方SDK和依赖:

go get google.golang.org/api/gmail/v1
go get golang.org/x/oauth2
go get golang.org/x/oauth2/google

核心实现说明

*关键踩坑点提前说明:Gmail发信接口要求传入的邮件内容必须使用**URL安全的无填充base64(RawURLEncoding)*编码,使用标准base64会直接返回400错误;邮件头必须严格遵循RFC 822规范,换行统一使用\r\n。

完整可运行代码如下:

package main

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/mail"
	"os"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/gmail/v1"
	"google.golang.org/api/option"
)

// 读取本地凭证初始化Gmail服务客户端
func getGmailService() (*gmail.Service, error) {
	b, err := ioutil.ReadFile("credentials.json")
	if err != nil {
		return nil, fmt.Errorf("读取credentials.json失败: %w", err)
	}

	// 仅配置发信权限
	config, err := google.ConfigFromJSON(b, gmail.GmailSendScope)
	if err != nil {
		return nil, fmt.Errorf("解析凭证配置失败: %w", err)
	}

	tokFile := "token.json"
	tok, err := tokenFromFile(tokFile)
	if err != nil {
		tok = getTokenFromWeb(config)
		saveToken(tokFile, tok)
	}

	client := config.Client(context.Background(), tok)
	srv, err := gmail.NewService(context.Background(), option.WithHTTPClient(client))
	if err != nil {
		return nil, fmt.Errorf("创建Gmail服务失败: %w", err)
	}
	return srv, nil
}

// 走浏览器授权流程获取token
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
	authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
	fmt.Printf("请打开以下链接完成授权: \n%v\n", authURL)
	fmt.Print("输入授权后页面返回的授权码: ")

	var authCode string
	if _, err := fmt.Scan(&authCode); err != nil {
		log.Fatalf("读取授权码失败: %v", err)
	}

	tok, err := config.Exchange(context.TODO(), authCode)
	if err != nil {
		log.Fatalf("换取token失败: %v", err)
	}
	return tok
}

// 从本地文件读取已保存的token
func tokenFromFile(file string) (*oauth2.Token, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	tok := &oauth2.Token{}
	err = json.NewDecoder(f).Decode(tok)
	return tok, err
}

// 持久化token到本地
func saveToken(path string, token *oauth2.Token) {
	fmt.Printf("保存凭证到: %s\n", path)
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		log.Fatalf("无法写入token文件: %v", err)
	}
	defer f.Close()
	json.NewEncoder(f).Encode(token)
}

// 发信方法
func SendEmail(to, subject, body string) error {
	srv, err := getGmailService()
	if err != nil {
		return err
	}

	// 构造RFC 822标准格式邮件
	from := mail.Address{Name: "发件人名称", Address: "你的Gmail邮箱地址@gmail.com"}
	toAddr := mail.Address{Address: to}
	
	msg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nContent-Type: text/plain; charset=\"UTF-8\"\r\n\r\n%s",
		from.String(), toAddr.String(), subject, body)

	// 必须使用RawURLEncoding编码
	rawMsg := base64.RawURLEncoding.EncodeToString([]byte(msg))
	gmailMsg := &gmail.Message{
		Raw: rawMsg,
	}

	// me代表当前授权的账号
	_, err = srv.Users.Messages.Send("me", gmailMsg).Do()
	if err != nil {
		return fmt.Errorf("调用发信接口失败: %w", err)
	}
	return nil
}

func main() {
	err := SendEmail("收件人邮箱@xxx.com", "测试邮件标题", "这是通过Golang调用Gmail API发送的测试邮件内容")
	if err != nil {
		log.Fatalf("发信失败: %v", err)
	}
	log.Println("邮件发送成功")
}

常见问题排查

  • 首次运行程序会自动输出授权链接,复制到浏览器登录你的Gmail账号完成授权,将页面返回的授权码粘贴回终端即可,授权成功后会在本地生成token.json保存凭证,后续运行不需要重复授权
  • 报错invalid_grant:先检查本地系统时间是否和网络时间同步,无效的话删除token.json重新走授权流程即可
  • 报错403 Forbidden:确认Gmail API已经在云控制台启用,OAuth凭证类型选的是桌面应用,权限范围没有配置错误
  • 报错400 Bad Request:优先检查邮件编码方式是否正确,邮件头格式是否符合规范
  • 需要发送HTML邮件时,仅需把Content-Type改为text/html; charset="UTF-8",正文传入HTML代码即可;需要添加附件的话构造multipart格式邮件,编码规则保持一致即可

内容的提问来源于stack exchange,提问作者Bryan Ho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 21:09:17