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

Spring Boot集成Gmail API异常:Gmail.Builder执行无响应求助

搭建Gmail邮件发送服务的异常排查求助

我是Spring Boot新手,正在搭建Gmail邮件发送服务,参考第三方仓库代码但无法正常运行。官方文档通过JSON文件传递凭证,我改用对象传递凭证的方式,尝试过ChatGPT仍未解决问题。

调试发现AccessToken和Credential对象均可正常生成,但执行Gmail.Builder代码时程序无响应、无任何报错,调试模式下会抛出InvocationTargetException。

相关代码

GmailService类

@Data
@Service
public class GmailService {

    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
    private HttpTransport httpTransport;
    private GmailCredential gmailCredential;
    @Value("${spring.security.oauth2.client.registration.google.client-id}")
    private String clientId;
    @Value("${spring.security.oauth2.client.registration.google.client-secret}")
    private String secretKey;
    private String refreshToken;
    private String fromEmail;
    private String toEmail;


    @SneakyThrows
    public GmailService() {

        this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();

        this.gmailCredential = new GmailCredential(
                clientId,
                secretKey,
                refreshToken,
                null,
                null,
                fromEmail
        );

    }

    public boolean sendMessage(
            String subject,
            String body,
            MultipartFile attachment) throws MessagingException, IOException {

        refreshAccessToken();

        Message message = createMessageWithEmail(
                createEmail(toEmail, gmailCredential.userEmail(), subject, body));

        return createGmail()
                .users()
                .messages()
                .send(gmailCredential.userEmail(), message)
                .execute()
                .getLabelIds()
                .contains("SENT");

    }

    private Gmail createGmail() {

        TokenResponse tokenResponse = refreshAccessToken();
        Credential credential = authorize();
//        // Create GoogleCredential from the TokenResponse
//        GoogleCredential credential = new GoogleCredential.Builder()
//                .setTransport(httpTransport)
//                .setJsonFactory(JSON_FACTORY)
//                .setClientSecrets(clientId, secretKey)
//                .build()
//                .setAccessToken(tokenResponse.getAccessToken());

        return new Gmail.Builder(httpTransport, JSON_FACTORY, credential)
                .build();

    }

    private MimeMessage createEmail(
            String to,
            String from,
            String subject,
            String bodyText) throws MessagingException {

        MimeMessage email = new MimeMessage(Session.getDefaultInstance(new Properties(), null));

        email.setFrom(new InternetAddress(from));

        email.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to));

        email.setSubject(subject);

        email.setText(bodyText);

        return email;

    }


    private Message createMessageWithEmail(MimeMessage emailContent)
            throws MessagingException, IOException {

        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        emailContent.writeTo(buffer);

        return new Message()
                .setRaw(Base64.encodeBase64URLSafeString(buffer.toByteArray()));
    }

    private Credential authorize() {

        try {

            TokenResponse tokenResponse = refreshAccessToken();

            return new Credential(BearerToken.authorizationHeaderAccessMethod()).setFromTokenResponse(
                    tokenResponse);

        } catch (Exception e) {

            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "Not able to process request.");

        }

    }

    private TokenResponse refreshAccessToken() {

        RestTemplate restTemplate = new RestTemplate();

        GmailCredential gmailCredentialsDto = new GmailCredential(
                clientId,
                secretKey,
                refreshToken,
                "refresh_token",
                null,
                null
        );

        HttpEntity<GmailCredential> entity = new HttpEntity(gmailCredentialsDto);

        try {

            GoogleTokenResponse response = restTemplate.postForObject(
                    "https://www.googleapis.com/oauth2/v4/token",
                    entity,
                    GoogleTokenResponse.class);
            System.out.println("request sucess234wefull ");

            gmailCredential = new GmailCredential(
                    clientId,
                    secretKey,
                    refreshToken,
                    null,
                    response.getAccessToken(),
                    fromEmail
            );
            System.out.println("request sucessfull ");
            return response;

        } catch (Exception e) {

            e.printStackTrace();

            throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                    "Not able to process request.");

        }
    }

}

GmailCredential记录类

package com.lemon.worker.utils;

import lombok.Data;

import javax.annotation.Nullable;

public record GmailCredential(
        @Nullable
        String client_id,
        @Nullable
        String client_secret,
        @Nullable
        String refresh_token,
        @Nullable
        String grant_type,
        @Nullable
        String access_token,
        @Nullable
        String userEmail
) {

        public String getAccessToken() {
                return "something";
        }
}

GoogleTokenResponse类

package com.lemon.worker.utils;


import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.util.Key;

public class GoogleTokenResponse extends TokenResponse {

    @Key("expires_in")
    private Integer expiresInSeconds;
}

调试时抛出的异常

@Nullable
    public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) throws Throwable {
        try {
            Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
            ReflectionUtils.makeAccessible(originalMethod);
            return coroutinesReactorPresent && KotlinDetector.isSuspendingFunction(originalMethod) ? AopUtils.KotlinDelegate.invokeSuspendingFunction(originalMethod, target, args) : originalMethod.invoke(target, args);
        } catch (InvocationTargetException ex) {
            throw ex.getTargetException(); // <----- 此处抛出异常
        } catch (IllegalArgumentException ex) {
            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + String.valueOf(method) + "] on target [" + String.valueOf(target) + "]", ex);
        } catch (IllegalAccessException ex) {
            throw new AopInvocationException("Could not access method [" + String.valueOf(method) + "]", ex);
        }
    }

补充说明

已确认AccessToken已正确生成并存入Credential对象,请求帮忙排查问题所在。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:05:08