javax.mail.AuthenticationFailedException: 535-5.7.8 用户名和密码不被接受

javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted

standalone-full-ha.xml 中的邮件服务配置。

<subsystem xmlns="urn:jboss:domain:mail:2.0">
    <mail-session name="default" jndi-name="java:jboss/mail/Default" from="sender@gmail.com">
        <smtp-server outbound-socket-binding-ref="mail-smtp" ssl="true" username="User" password="password"/>
    </mail-session>
</subsystem>

邮件 Session 又引用了绑定在本地主机 465 端口的 SMTP 主机。

<outbound-socket-binding name="mail-smtp">
    <remote-destination host="smtp.gmail.com" port="465"/>
</outbound-socket-binding>

配置中使用的实际密码是在 https://security.google.com/settings/security/apppasswords

的“两步验证”期间生成的应用程序专用密码

进行此配置后,尝试使用以下代码发送电子邮件会引发异常。

@Resource(mappedName = "java:jboss/mail/Default")
private Session mailSession;

public void init() throws AddressException, MessagingException {
    MimeMessage m = new MimeMessage(mailSession);
    Address from = new InternetAddress("sender@gmail.com");
    Address[] to = new InternetAddress[]{new InternetAddress("receiver@gmail.com")};

    m.setFrom(from);
    m.setRecipients(Message.RecipientType.TO, to);
    m.setSubject("Message Subject");
    m.setSentDate(new Date());
    m.setContent("Mail sent from app", "text/html");
    Transport.send(m);
}

抛出以下异常。

07:48:36,906 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (default task-9) #{countryManagedBean.init}: javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8  https://support.google.com/mail/answer/14257 t70sm5413631pfi.8 - gsmtp
: javax.faces.FacesException: #{countryManagedBean.init}: javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8  https://support.google.com/mail/answer/14257 t70sm5413631pfi.8 - gsmtp

    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
    at javax.faces.component.UIViewAction.broadcast(UIViewAction.java:562)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:130)
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:78)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at io.undertow.websockets.jsr.JsrWebSocketFilter.doFilter(JsrWebSocketFilter.java:151)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at org.omnifaces.facesviews.FacesViewsForwardingFilter.filterExtensionLess(FacesViewsForwardingFilter.java:128)
    at org.omnifaces.facesviews.FacesViewsForwardingFilter.doFilter(FacesViewsForwardingFilter.java:89)
    at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at filter.NoCacheFilter.doFilter(NoCacheFilter.java:33)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at org.omnifaces.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:122)
    at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.DisableCacheHandler.handleRequest(DisableCacheHandler.java:33)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
    at io.undertow.servlet.handlers.ServletInitialHandler.access[=14=]0(ServletInitialHandler.java:80)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:172)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
    at io.undertow.server.HttpServerExchange.run(HttpServerExchange.java:774)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: javax.faces.el.EvaluationException: javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8  https://support.google.com/mail/answer/14257 t70sm5413631pfi.8 - gsmtp

    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
    ... 57 more
Caused by: javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8  https://support.google.com/mail/answer/14257 t70sm5413631pfi.8 - gsmtp

    at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:892)
    at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:814)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:728)
    at javax.mail.Service.connect(Service.java:386)
    at javax.mail.Service.connect(Service.java:245)
    at javax.mail.Service.connect(Service.java:194)
    at javax.mail.Transport.send0(Transport.java:253)
    at javax.mail.Transport.send(Transport.java:124)
    at admin.bean.CountryManagedBean.init(CountryManagedBean.java:81)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:292)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
    ... 58 more

使用 WildFly 9.0.2 final(使用自签名 SSL 证书的应用程序在这里应该不是问题)。

在不正确的假设下出现配置错误。 XML 属性 username 需要实际的电子邮件地址,其中给出了相应发件人帐户的屏幕名称,因此是例外。如下修改后正常使用

<mail-session name="default" jndi-name="java:jboss/mail/Default" from="sender@gmail.com">
    <smtp-server outbound-socket-binding-ref="mail-smtp" ssl="true" username="sender@gmail.com" password="password"/>
</mail-session>

配置中使用的实际密码是在 https://security.google.com/settings/security/apppasswords 的“两步验证”期间生成的应用程序特定密码,如问题中所述。

邮件会话 javax.mail.Session 然后可以使用 javax.annotation.Resource 注释。

由于某些未知原因而没有发生的一件事是 from XML 属性指定的发件人姓名(标签)。它总是将发件人的电子邮件地址作为发件人姓名发送,这是意外的。即使做,

Address from = new InternetAddress("admin@server.domain");
mimeMessage.setFrom(from);

没有帮助。我遵循了 this answer 中建议的一些模式,但它也没有帮助。但是,它适用于 Java SE 环境。然而,这与当前问题不同。也许,我稍后会问一个单独的问题。


补充:

我更喜欢 JMS 队列作为后台进程异步发送邮件,因为发送邮件可能由于多种原因而显着延迟。实际消息连同收件人的电子邮件地址通过 JMS 队列发送,实际邮件从相应队列的接收终端内传送到目标邮件服务器,如下所示。

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true"),
    @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:jboss/exported/jms/emailQueue"),
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
@RunAs("ROLE_ADMIN")
public class MailBean implements MessageListener {

    @Resource(lookup = "java:jboss/mail/Default")
    private Session mailSession; // javax.jms.Session

    @Override
    @PermitAll
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void onMessage(Message message) {

        try {
            if (message instanceof ObjectMessage) {
                ObjectMessage objectMessage = (ObjectMessage) message;

                EmailUtil emailUtil = (EmailUtil) objectMessage.getObject();
                String receiver = emailUtil.getReceiver();
                String textMessage = emailUtil.getMessage();

                if (StringUtils.isNotBlank(receiver) && StringUtils.isNotBlank(textMessage)) {
                    MimeMessage mimeMessage = new MimeMessage(mailSession);
                    Address[] to = new InternetAddress[]{new InternetAddress(receiver)};

                    mimeMessage.setRecipients(javax.mail.Message.RecipientType.TO, to);
                    mimeMessage.setSubject(emailUtil.getSubject(), "UTF-8");
                    mimeMessage.setSentDate(new Date());
                    mimeMessage.setText(textMessage, "UTF-8", "html");
                    Transport.send(mimeMessage);
                } else {
                    System.out.println("No message found.");
                }
            } else {
                System.out.println("Message is of wrong type : " + message.getClass().getName());
            }
        } catch (JMSException | MessagingException e) {
            Logger.getLogger(MailBean.class.getName()).log(Level.SEVERE, null, e);
        }
    }
}

EmailUtil 是一个实用程序 Java class 持有必要的属性并实现 java.io.Serializable 接口(发送可序列化的 Java 对象是必需的)。

public final class EmailUtil implements Serializable {

    private String message;
    private String subject;
    private String receiver;
    private static final long serialVersionUID = 1L;

    // Constructor(s) + getters + setters + hashCode() + equals() + toString().
}

为了注入 Queue,我使用应用程序范围的 CDI 托管 bean 以在前端实现更好的可重用性。

@ApplicationScoped
public class EmailQueueBean {

    @Resource(lookup = "java:jboss/exported/jms/emailQueue")
    private Queue queue;
    @Resource(lookup = "java:jboss/exported/jms/emailFactory")
    private ConnectionFactory connectionFactory;

    public EmailQueueBean() {}

    public void send(EmailUtil emailUtil) throws JMSException {
        try (Connection connection = connectionFactory.createConnection("admin@gmail.com", "admin_password");
                javax.jms.Session session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
                MessageProducer producer = session.createProducer(queue)) {
            ObjectMessage objectMessage = session.createObjectMessage(emailUtil);
            producer.send(objectMessage);
        }
    }
}

在任何 Java EE 工件中的任何位置注入此 bean,使用 new 手动构建 EmailUtil 的实例,并代表注入的代理调用 send() 方法通过 EmailUtil 构造的实例传递托管 bean 的实例。

不需要使用 createConnection() 方法指定的 username / password 进行身份验证(在 MDB 之前也不需要 @RunAs("ROLE_ADMIN")),以防禁用安全性/ 在配置中的 hornetq server 中没有使用。

另请参阅: