JHipster MailService - javax.mail.SendFailedException: No recipient addresses

4.6k views Asked by At

UPDATE: Hello Guys,

I was finally able to resolve this problem by changing how I added a recipient. Not sure why this works as opposed to the boiler plate but this allowed me to pass this hurdle. Hope this provides help to those experiencing similar issues.

@Async
public void sendEmail(String to, String sendFrom, String subject, String content) {
    log.debug("Send e-mail to '{}' with subject '{}' and content={}",
            to, subject, content);

    // Prepare message using a Spring helper
    MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    try {
        mimeMessage.setRecipients(Message.RecipientType.TO, to);
        mimeMessage.setContent(content, MediaType.TEXT_HTML_VALUE);
        mimeMessage.setFrom(new InternetAddress(sendFrom));
        mimeMessage.setSubject(subject);

        javaMailSender.send(mimeMessage);
        log.debug("Sent e-mail to '{}'", to);
    } catch (Exception e) {
        log.warn("E-mail could not be sent to '{}', exception is: {}", to, e.getMessage());
    }
}

ORIGINAL POST

After several days of researching and reaching out to more senior developers I know, I am finally coming here for help. Any input or help is greatly appreciated!

I'm using the MailService provided with the JHipster stack.

The application is using my personal email. It has 2 step authentication so I do not need to allow less secure apps as I'm directly giving my app a password through app passwords. IMAP and POP are enabled.

From what I can tell I am able to connect correctly, I just can't send to a recipient. I have tried different emails at different domains with no luck. If I change the app password to my raw password it complains saying it must use an app specific password. So This leads me to be sure I'm authenticating/connecting correctly.

Pulling sources and debugging brought me to doSend in the JavaMailSenderImpl and the error specifically is thrown by mimeMessage.getAllRecipients()

My console shows:

[DEBUG] com.myapp.aop.logging.LoggingAspect - Enter: com.myapp.service.MailService.sendEmail() with argument[s] = [[email protected], [email protected], hi, false, true]
[DEBUG] com.myapp.service.MailService - Send e-mail[multipart 'false' and html 'true'] to '[email protected]' with subject 'subjecthi' and content=hi
[DEBUG] com.sun.mail.smtp - useEhlo true, useAuth true
[DEBUG] com.sun.mail.smtp - trying to connect to host "smtp.gmail.com", port 587, isSSL false
[DEBUG] com.sun.mail.smtp - connected to host "smtp.gmail.com", port: 587

[DEBUG] com.sun.mail.smtp - Found extension "SIZE", arg "35882577"
[DEBUG] com.sun.mail.smtp - Found extension "8BITMIME", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "STARTTLS", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "ENHANCEDSTATUSCODES", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "PIPELINING", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "CHUNKING", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "SMTPUTF8", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "SIZE", arg "35882577"
[DEBUG] com.sun.mail.smtp - Found extension "8BITMIME", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "AUTH", arg "LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN XOAUTH"
[DEBUG] com.sun.mail.smtp - Found extension "ENHANCEDSTATUSCODES", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "PIPELINING", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "CHUNKING", arg ""
[DEBUG] com.sun.mail.smtp - Found extension "SMTPUTF8", arg ""
[DEBUG] com.sun.mail.smtp - Attempt to authenticate using mechanisms: LOGIN     PLAIN DIGEST-MD5 NTLM 
[WARN] com.myapp.service.MailService - E-mail could not be sent to user     '[email protected]', exception is: Failed messages:     javax.mail.SendFailedException: No recipient addresses
[DEBUG] com.myapp.aop.logging.LoggingAspect - Exit:     com.myapp.service.MailService.sendEmail() with result = null

I am providing the following files:

  • application.yml
  • MailConfiguration.java
  • MailService.java
  • call from my OrderResource.java to the MailService

application.yml

# Disable the spring security default configuration from spring-boot-actuator
management.security.enabled: true
security.basic.enabled: false

# Disable Jolokia - An http/json bridge for remote JMX access
endpoints.jolokia.enabled: false

# security configuration (this key should be unique for your application, and kept secret)
jhipster.security.rememberme.key: securitykey

StripeSecretApiKey: mystripekey

async:
    corePoolSize: 2
    maxPoolSize: 50
    queueCapacity: 10000

mail:
    host: smtp.gmail.com
    port: 587
    username: [email protected]
    password: myapppassword
    protocol: smtp
    tls: true
    auth: true
    from: [email protected]

authentication:
    oauth:
        clientid: mydomainapp
        secret: mysecret
        # Token is valid 2 hours
        tokenValidityInSeconds: 7200

swagger:
    title: mydomain API
    description: mydomain applications and beyond!
    termsOfServiceUrl: http://jhipster.github.io/
    contact:
    license: Apache 2.0
    licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.html

OrderResource.java call to mail service

mailService.sendEmail("[email protected]", "subject hi", "hi",false, true);

MailConfiguration.java

package com.myapp.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import java.util.Properties;

@Configuration
public class MailConfiguration implements EnvironmentAware {

    private static final String ENV_SPRING_MAIL = "mail.";
    private static final String DEFAULT_HOST = "127.0.0.1";
    private static final String PROP_HOST = "host";
    private static final String DEFAULT_PROP_HOST = "localhost";
    private static final String PROP_PORT = "port";
    private static final String PROP_USER = "username";
    private static final String PROP_PASSWORD = "password";
    private static final String PROP_PROTO = "protocol";
    private static final String PROP_TLS = "tls";
    private static final String PROP_AUTH = "auth";
    private static final String PROP_SMTP_AUTH = "mail.smtp.auth";
    private static final String PROP_STARTTLS = "mail.smtp.starttls.enable";
    private static final String PROP_TRANSPORT_PROTO =         "mail.transport.protocol";

    private final Logger log = LoggerFactory.getLogger(MailConfiguration.class);

    private RelaxedPropertyResolver propertyResolver;

    @Override
    public void setEnvironment(Environment environment) {
    this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_SPRING_MAIL);
    }

    @Bean
    public JavaMailSenderImpl javaMailSender() {
        log.debug("Configuring mail server");
    String host = propertyResolver.getProperty(PROP_HOST, DEFAULT_PROP_HOST);
    int port = propertyResolver.getProperty(PROP_PORT, Integer.class, 0);
    String user = propertyResolver.getProperty(PROP_USER);
    String password = propertyResolver.getProperty(PROP_PASSWORD);
    String protocol = propertyResolver.getProperty(PROP_PROTO);
    Boolean tls = propertyResolver.getProperty(PROP_TLS, Boolean.class, false);
    Boolean auth = propertyResolver.getProperty(PROP_AUTH, Boolean.class, false);

    JavaMailSenderImpl sender = new JavaMailSenderImpl();
    if (host != null && !host.isEmpty()) {
        sender.setHost(host);
    } else {
        log.warn("Warning! Your SMTP server is not configured. We will try to use one on localhost.");
        log.debug("Did you configure your SMTP settings in your application.yml?");
        sender.setHost(DEFAULT_HOST);
    }

    sender.setPort(port);
    sender.setUsername(user);
    sender.setPassword(password);

    Properties sendProperties = new Properties();
    sendProperties.setProperty(PROP_SMTP_AUTH, auth.toString());
    sendProperties.setProperty(PROP_STARTTLS, tls.toString());
    sendProperties.setProperty(PROP_TRANSPORT_PROTO, protocol);
    sender.setJavaMailProperties(sendProperties);
    return sender;
   }
}

MailService.java

package com.myapp.service;

import com.myapp.domain.User;
import org.apache.commons.lang.CharEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.core.env.Environment;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring4.SpringTemplateEngine;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.mail.Message;
import javax.mail.SendFailedException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Locale;

/**
 * Service for sending e-mails.
 * <p/>
 * <p>
 * We use the @Async annotation to send e-mails asynchronously.
 * </p>
 */
@Service
public class MailService {

    private final Logger log = LoggerFactory.getLogger(MailService.class);

    @Inject
    private Environment env;

    @Inject
    private JavaMailSenderImpl javaMailSender;

    @Inject
    private MessageSource messageSource;

    @Inject
    private SpringTemplateEngine templateEngine;

    /**
     * System default email address that sends the e-mails.
     */
    private String from;

    @PostConstruct
    public void init() {
        this.from = env.getProperty("mail.from");
    }

    @Async
    public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
        log.debug("Send e-mail[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
            isMultipart, isHtml, to, subject, content);

        // Prepare message using a Spring helper
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, CharEncoding.UTF_8);
            message.setTo(to);
            message.setFrom(from);
            message.setSubject(subject);
            message.setText(content, isHtml);
            javaMailSender.send(message.getMimeMessage());
            log.debug("Sent e-mail to User '{}'", to);
        } catch (Exception e) {
            log.warn("E-mail could not be sent to user '{}', exception is: {}", to, e.getMessage());
        }
    }

    @Async
    public void sendPurchaseEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
        log.debug("Send e-mail[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
        isMultipart, isHtml, to, subject, content);

        // Prepare message using a Spring helper
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, CharEncoding.UTF_8);
            message.setTo(to);
            message.setFrom(from);
            message.setSubject(subject);
            message.setText(content, isHtml);
            javaMailSender.send(message.getMimeMessage());
            log.debug("Sent purchase e-mail to '{}'", to);
        } catch (Exception e) {
            log.warn("E-mail could not be sent to '{}', exception is: {}", to, e.getMessage());
        }
    }

    @Async
    public void sendActivationEmail(User user, String baseUrl) {
        log.debug("Sending activation e-mail to '{}'", user.getEmail());
        Locale locale = Locale.forLanguageTag(user.getLangKey());
        Context context = new Context(locale);
        context.setVariable("user", user);
        context.setVariable("baseUrl", baseUrl);
        String content = templateEngine.process("activationEmail", context);
        String subject = messageSource.getMessage("email.activation.title", null, locale);
        sendEmail(user.getEmail(), subject, content, false, true);
    }

    @Async
    public void sendPurchaseNotificationEmail(String orderId, String email, String baseUrl) {
        log.debug("Sending activation e-mail to '{}'", email);
        Locale locale = Locale.forLanguageTag(Locale.ENGLISH.getLanguage());

        String title = messageSource.getMessage("email.purchase.title", null, locale);

        Context context = new Context(locale);
        context.setVariable("orderId", orderId);
        context.setVariable("baseUrl", baseUrl);
        context.setVariable("subject", title);
        context.setVariable("greeting", messageSource.getMessage("email.purchase.greeting", null, locale));
        context.setVariable("text1", messageSource.getMessage("email.purchase.text1", null, locale));
        context.setVariable("text2", messageSource.getMessage("email.purchase.text2", null, locale));
        context.setVariable("signature", messageSource.getMessage("email.purchase.signature", null, locale));

        String content = templateEngine.process("purchaseEmail", context);
        sendPurchaseEmail(email, title, content, false, true);
    }
}
1

There are 1 answers

0
Eric Foster On

Another Update: Today I stumbled upon this post which enlightened me to a one line addition mimeMessage.saveChanges() that appears to resolve my previous issue. Kudos to @dkar for his answer that finally rectified this issue for me as well. Read his answer here: Original Answer

@Async
public void sendEmail(String to, String sendFrom, String subject, String content) {
    log.debug("Send e-mail to '{}' with subject '{}' and content={}",
            to, subject, content);

    // Prepare message using a Spring helper
    MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    try {
        MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, CharEncoding.UTF_8);
        message.setTo(to);
        message.setFrom(sendFrom);
        message.setSubject(subject);
        message.setText(content, true);
        mimeMessage.saveChanges();
        javaMailSender.send(message.getMimeMessage());
        log.debug("Sent e-mail to User '{}'", to);
    } catch (Exception e) {
        log.warn("E-mail could not be sent to user '{}', exception is: {}", to, e.getMessage());
    }
}