0

I create a class to manage sending emails and i want to inject smtp config via properties file. But i keep got null on my field properties. This is my code:

public class EmailUtils { 
    @Inject
    @PropertiesFromFile("smtp.properties")
    Properties properties;

    public void sendEmail(String destinator, String subject, String body) {
        final String username = properties.getProperty("smtp.email");
        final String password = properties.getProperty("smtp.password");

        Session session = Session.getInstance(properties,
          new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
          });

        try {

            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(properties.getProperty("smtp.from")));
            message.setRecipients(Message.RecipientType.TO,
                InternetAddress.parse(destinator));
            message.setSubject(subject);
            message.setText(body);

            Transport.send(message);

            System.out.println("Done");

        } catch (MessagingException e) {
            throw new RuntimeException(e);
        }
   }
}

public class PropertyReader {

    @Produces
    @PropertiesFromFile
    public Properties provideServerProperties(InjectionPoint ip) {
    //get filename from annotation
    String filename = ip.getAnnotated().getAnnotation(PropertiesFromFile.class).value();
    return readProperties(filename);
}

    private Properties readProperties(String fileInClasspath) {
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileInClasspath);

        try {
            Properties properties = new Properties();
            properties.load(is);
            return properties;
       } catch (IOException e) {
           System.err.println("Could not read properties from file " + fileInClasspath + " in classpath. " + e);
       } catch (Exception e) {
           System.err.println("Exception catched:"+ e.getMessage());
       } 

       return null;
   }
}

@Qualifier
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface PropertiesFromFile {
    @Nonbinding
    String value() default "application.properties";
}

I tested the code with a simple Main, but it doesn't work. I tested it with tomcat and still got NPE on Properties object. I missed something ? Please help :)

Steve C
  • 17,352
  • 4
  • 29
  • 34
Khairy
  • 71
  • 9

2 Answers2

3

Please consider doing this Java EE way:

  1. If using Tomcat then ensure that you have set it up with a CDI implementation as described in How to install and use CDI on Tomcat? or Application servers and environments supported by Weld.

  2. Move the JavaMail implementation jars from your application's WEB-INF/lib to the Tomcat lib directory.

  3. Configure your email session in Tomcat by adding the following to it's config/Context.xml file:

    <Context>
        ...
        <Resource name="mail/Session" auth="Container"
          type="javax.mail.Session"
          mail.smtp.host="your mail host here"
          mail.smtp.user="your user name here"
          password="your password"
          mail.from="noreply@yourdomain.com" />
        ...
    </Context>   
    

    There are other places to put this configuration but this is the simplest to explain here. Refer to the Tomcat JNDI documentation for more information.

  4. Simplify your code:

        @Resource(name="mail/Session")
        private Session session;
    
        public void sendEmail(String destinator, String subject, String body) {
            try {
    
                Message message = new MimeMessage(session);
                message.setRecipients(Message.RecipientType.TO,
                        InternetAddress.parse(destinator));
                message.setSubject(subject);
                message.setText(body);
    
                Transport.send(message);
    
                System.out.println("Done");
    
            } catch (MessagingException e) {
                throw new RuntimeException(e);
            }
        }
    

    Your server (Tomcat in this case) looks after configuring the mail session and authentication for you.

A similar mechanism applies to setting up JDBC DataSource objects FWIW.

Steve C
  • 17,352
  • 4
  • 29
  • 34
  • Thank you Steve,I use maven3 to manage dependencies, is there another way to solve the issues ? – Khairy Sep 10 '17 at 10:38
  • 1
    At the very least you need to get CDI working in Tomcat. Step 1 gives you pointers for that. Life would be easier for you if you used Tomee, WildFly or Payara servers though.Then you could ignore step 1. – Steve C Sep 10 '17 at 13:36
2

Annotate your PropertyReader class with @Named and @ApplicationScoped to make it known to the CDI Container so it can be managed. Have a blank beans.xml in your class path.

Ndumiso
  • 222
  • 2
  • 13