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
依次引用绑定在localhost端口465的SMTP主机。
<outbound-socket-binding name="mail-smtp">
<remote-destination host="smtp.gmail.com" port="465"/>
</outbound-socket-binding>
配置中使用的实际密码是在&#34; 2-Step Verification&#34;期间生成的应用专用密码。在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$000(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange$1.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证书的应用程序不应该成为问题)。
答案 0 :(得分:1)
在错误的假设中存在配置错误。 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
注入任何Java EE工件,如Servlet,Servlet过滤器,托管bean,EJB,消息驱动Bean(MDB)等。
由于某些未知原因而未发生的一件事是使用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类,它包含必要的属性并实现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,使用EmailUtil
手动构造new
实例,并代表托管bean传入的注入代理实例调用send()
方法通过构造EmailUtil
的实例。
如果禁用安全性,则不需要使用username
方法指定的password
/ createConnection()
进行身份验证(在MDB之前也不需要@RunAs("ROLE_ADMIN")
)用于配置中的hornetq服务器。
另见: