我有一个Node.js批处理,该批处理处理用户列表,并为每个用户向Java后端进行API调用。 Node.js批处理和Java后端都使用G-Suite帐户向用户发送邮件。
Node.js没问题,所有邮件都成功。关于Java,在发送了一定数量的邮件之后,以下邮件失败,并显示以下消息:
org.springframework.mail.MailAuthenticationException: Authentication
failed; nested exception is javax.mail.AuthenticationFailedException:
334
eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==
; nested exception is: javax.mail.AuthenticationFailedException:
OAUTH2 asked for more at
org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:424)
at
org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:345)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:340)
Base64解码后给出的内容:
{“状态”:“ 400”,“方案”:“承载者”,“范围”:“ https://mail.google.com/”}
以下是我实现的一些细节。
@Service
public class MailServiceImpl implements MailService {
@Autowired
private JavaMailSender javaMailSender;
@Value("${fr.app.email.service-account}")
private String serviceAccount;
@Value("${fr.app.email.scope}")
private String scope;
private Credential creds;
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy à HH:mm");
@Async
public CompletableFuture<Void> sendSimpleMail(String email, String subject, String text) throws Exception {
if(creds == null) {
final HttpTransport TRANSPORT = new NetHttpTransport();
final JsonFactory JSON_FACTORY = new JacksonFactory();
final URL URL = Thread.currentThread().getContextClassLoader().getResource("MyApp-d8a5d9785c54.p12");
creds = new GoogleCredential.Builder()
.setTransport(TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(serviceAccount)
.setServiceAccountPrivateKeyFromP12File(new File(URL.getFile()))
.setServiceAccountScopes(Collections.singleton(scope))
.setServiceAccountUser(((JavaMailSenderImpl)javaMailSender).getUsername())
.build();
}
if(creds.getExpiresInSeconds() != null && creds.getExpiresInSeconds() < 0 || creds.getAccessToken() == null) {
creds.refreshToken();
}
try {
((JavaMailSenderImpl)javaMailSender).setDefaultEncoding("UTF-8");
((JavaMailSenderImpl)javaMailSender).setPassword(creds.getAccessToken());
Message message = new MimeMessage(((JavaMailSenderImpl)javaMailSender).getSession());
message.setFrom(new InternetAddress(((JavaMailSenderImpl)javaMailSender).getUsername()));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email));
message.setSubject(subject);
message.setContent(text, "text/html; charset=UTF-8");
javaMailSender.send((MimeMessage)message);
return CompletableFuture.completedFuture(null);
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
}
以及有效的Node.js实现:
const { google } = require('googleapis');
// configure a JWT auth client
let jwtClient = new google.auth.JWT(
config.appServiceAccount,
config.googleKeyFile,
null,
[config.googleScope],
config.appMail
);
logger.info('Gmail client created!');
const gmail = google.gmail({ version: "v1", auth: jwtClient });
function sendMail(gmail, jwtClient, to, subject, message) {
let headers = {
"To": to,
"Subject": subject,
"Content-Type": "text/html; charset=UTF-8"
}
let email = '';
for (var header in headers)
email += header += ": " + headers[header] + "\r\n";
email += "\r\n" + message;
return gmail.users.messages.send({
auth: jwtClient,
userId: config.appMail,
requestBody: {
raw: btoa(email).replace(/\+/g, '-').replace(/\//g, '_')
}
});
}
由于有了mail.debug=true
配置键,我有了有关该错误的更多详细信息:前80条消息产生以下输出:
DEBUG SMTP: protocolConnect login, host=smtp.gmail.com,
user=contact@example.com, password=<non-null> DEBUG SMTP: Attempt to
authenticate using mechanisms: XOAUTH2 DEBUG SMTP: Using mechanism
XOAUTH2 AUTH XOAUTH2 <access_token>
235 2.7.0 Accepted
以下消息产生输出:
DEBUG SMTP: protocolConnect login, host=smtp.gmail.com,
user=contact@example.com, password=<non-null> DEBUG SMTP: Attempt to
authenticate using mechanisms: XOAUTH2 DEBUG SMTP: Using mechanism
XOAUTH2 AUTH XOAUTH2 <exact same access_token>
334
eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==
DEBUG SMTP: AUTH XOAUTH2 failed, THROW:
javax.mail.AuthenticationFailedException: OAUTH2 asked for more
at com.sun.mail.smtp.SMTPTransport$OAuth2Authenticator.doAuth(SMTPTransport.java:1095)
at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:909)
at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:843)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:748)
关于the Node.js client implementation,主要区别在于Node.js似乎没有使用SMTP,而是调用了API。
我已经读过here,对于SMTP有特定的限制,但是由于错误消息非常不清楚(DDoS,每10分钟的消息,...),我无法确定达到了哪个限制。