2022年5月30日谷歌停用SMTP网关后 Java用Gmail API+Servlet/JSP发邮件
Java Servlet/JSP 环境下通过Gmail API实现邮件发送方案
谷歌2022年5月30日停止普通账号SMTP网关服务后,原有基于JavaMail直连smtp.gmail.com的方案已经失效,你可以按照以下步骤迁移到Gmail API实现发信,全程兼容传统Servlet、JSP开发环境,原有邮件内容构造逻辑基本不需要修改。
前置准备
- 登录谷歌云控制台创建新项目,搜索并启用「Gmail API」服务
- 进入「API和服务-凭据」页面创建服务账号,为服务账号分配邮件发送权限,下载生成的JSON格式凭据文件,存放到Web项目的
WEB-INF/conf目录下,不要放在静态资源可公开访问的路径 - 个人Gmail账号需要在邮箱设置中把服务账号添加为授权发件人;企业Workspace账号直接在管理后台给服务账号分配全域邮件发送权限即可
引入项目依赖
如果使用Maven管理依赖,在pom.xml中添加以下配置:
<!-- Gmail API 核心依赖 --> <dependency> <groupId>com.google.api-client</groupId> <artifactId>google-api-client</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>com.google.oauth-client</groupId> <artifactId>google-oauth-client-jetty</artifactId> <version>1.34.1</version> </dependency> <dependency> <groupId>com.google.apis</groupId> <artifactId>google-api-services-gmail</artifactId> <version>v1-rev20240109-2.0.0</version> </dependency> <!-- 兼容原有JavaMail的MIME消息构造依赖,无需重写邮件内容生成逻辑 --> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency>
非Maven项目直接下载对应jar包放到WEB-INF/lib目录即可。
封装Gmail发送工具类
工具类做全局单例初始化,避免重复创建客户端连接浪费资源,同时兼容原有JavaMail的邮件构造逻辑:
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.gmail.Gmail; import com.google.api.services.gmail.GmailScopes; import com.google.api.services.gmail.model.Message; import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.Base64; public class GmailSendUtil { // 替换为你自己的凭据文件实际路径、发件人邮箱 private static final String CREDENTIAL_PATH = "/你的项目部署路径/WEB-INF/conf/gmail-credential.json"; private static final String SENDER_EMAIL = "你的发件人邮箱@gmail.com"; private static final GsonFactory GSON_FACTORY = GsonFactory.getDefaultInstance(); private static final List<String> SCOPES = Collections.singletonList(GmailScopes.GMAIL_SEND); private static Gmail gmailService; // 静态块初始化Gmail客户端,项目启动时执行一次 static { try { NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(CREDENTIAL_PATH)) .createScoped(SCOPES); // 企业Workspace账号可删除下一行,个人账号必须指定授权发件人 credential = credential.createDelegated(SENDER_EMAIL); gmailService = new Gmail.Builder(httpTransport, GSON_FACTORY, credential) .setApplicationName("你的Web项目名称") .build(); } catch (Exception e) { e.printStackTrace(); } } /** * 邮件发送方法,调用逻辑和原有JavaMail写法一致 * @param to 收件人邮箱 * @param subject 邮件主题 * @param htmlContent 邮件正文,支持HTML格式 * @throws Exception 发送异常 */ public static void sendMail(String to, String subject, String htmlContent) throws Exception { // 以下MimeMessage构造逻辑和你之前SMTP方案的写法基本一致 Properties props = new Properties(); Session session = Session.getDefaultInstance(props, null); MimeMessage mimeMessage = new MimeMessage(session); mimeMessage.setFrom(new InternetAddress(SENDER_EMAIL)); mimeMessage.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to)); mimeMessage.setSubject(subject, "UTF-8"); mimeMessage.setContent(htmlContent, "text/html;charset=UTF-8"); // 转换为Gmail API要求的编码格式 ByteArrayOutputStream baos = new ByteArrayOutputStream(); mimeMessage.writeTo(baos); String encodedEmail = Base64.getUrlEncoder().encodeToString(baos.toByteArray()); Message message = new Message(); message.setRaw(encodedEmail); // 调用接口发送 gmailService.users().messages().send("me", message).execute(); } }
在Servlet/JSP中调用
直接在业务逻辑层调用工具类即可,不要在JSP页面中直接写凭据加载、客户端初始化逻辑,避免凭据泄露。Servlet中调用示例:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String receiveMail = request.getParameter("to"); String mailSubject = request.getParameter("subject"); String mailContent = request.getParameter("content"); try { GmailSendUtil.sendMail(receiveMail, mailSubject, mailContent); request.setAttribute("result", "邮件发送成功"); } catch (Exception e) { request.setAttribute("result", "邮件发送失败:" + e.getMessage()); } request.getRequestDispatcher("/result.jsp").forward(request, response); }
注意事项
- JSON凭据文件必须放在WEB-INF等外部无法直接访问的目录,一旦泄露他人可以直接操作你的Gmail发信
- 原有JavaMail的附件添加、抄送、密送等逻辑完全不需要修改,只要保留MimeMessage的构造部分即可,迁移成本极低
- 如果需要让访问用户用自己的Gmail账号发信,可以把服务账号模式换成OAuth2用户授权模式,第一次登录授权后保存refreshToken即可长期使用
- 生产环境建议给Gmail客户端初始化加异常重试逻辑,避免接口临时波动导致发信失败
内容的提问来源于stack exchange,提问作者Troll Liên quân
相关产品推荐
相关产品推荐

