Search code examples
classloaderjakarta-mail

javax.mail.NoSuchProviderException: smtp occurs when class is loaded from a custom class loader


I am working on a Java EE application with GlassFish as the application server. I have developed a pluggable addon for sending out emails(I have named it EmailProvider). For this, I am using late binding to load the EmailProvider jar at runtime. I have a custom URLClassLoader which loads the EmailProvider class file. The email provider has the JavaMail API to send out email. Here is the code snippet. This code works perfectly if I include the EmailProvider class in my Java EE application but throws an exception at Transport transport = session.getTransport("smtp"); saying "javax.mail.NoSuchProviderException: smtp"i f I load the class at runtime using the customClassLoader. I know that this is classloading issue. I am also loading the javax.mail.jar through the customloader. I think the problem is same classes(javax.mail.jar) are being loaded from two different classloaders. If I omit javax.mail.jar then I get ClassNotFoundException for the javax.mail classes

Class EmailProvider{
 try {
        Properties props = new Properties();

        props.put("mail.smtp.host", "IP ADDRESS");
        props.put("mail.smtp.starttls.enable", "false"); 
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.class", "com.sun.mail.smtp.SMTPTransport");

        Session session = Session.getInstance(props, null);

        session.setDebug(false);
        Provider provider = session.getProvider("smtp");
        javax.mail.Message message = new MimeMessage(session);

        InternetAddress addressFrom = new InternetAddress("[email protected]");
        message.setFrom(addressFrom);
        InternetAddress[] addressTo = new InternetAddress[1]; 
        addressTo[0] = new InternetAddress("[email protected]");
        //msg.setRecipients(javax.mail.Message.RecipientType.TO, addressTo);
        message.setSubject("Hello");
        message.setContent("testing..", "text/plain");
        session.setProvider(provider);            
        Transport transport = session.getTransport("smtp");
        transport.connect("IP ADDRESS", "domain\\username", "password");            
        transport.sendMessage(message, addressTo);


    } catch (Exception ex) {
        Logger.getLogger(SendEmail.class.getName()).log(Level.SEVERE, null, ex);
    } }

Solution

  • First, there's nothing named "JEE". The correct name is "Java EE".

    The problem is that JavaMail can't find the configuration file in the javax.mail.jar file. It uses the thread's context class loader's getResource() method to find it. Assuming you've set up your custom class loader so that your application class loader is the parent class loader, you can set the thread's context class loader to your custom class loader.