У меня есть пакет Node.js, который обрабатывает список пользователей и выполняет вызовы API для бэкэнда Java для каждого пользователя.Пакет 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 дает:
{"status": "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);
}
}
}
И рабочий узел.Реализация 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)
Относительно реализации клиента Node.js , основное отличие состоит в том, что Node.js, кажется, не использует SMTP, а вместо этого вызывает API.
Я прочитал здесь , что существуют определенные ограничения для SMTP, но я не могу понять, какое ограничение я достиг, потому что сообщение об ошибке очень неясно (DDoS, сообщений на 10минут, ...).