34

I am trying to build an email client app in android and right now i want to configure the javaMail part.

i am trying to establish the connection with the imap server but something is wrong with my code.. here is my code:

package mailpackage;

import java.util.Properties;

import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;

public class Connection implements Runnable
{
    boolean done;

    public Connection()
    {
        this.done=false;
    }

    @Override
    public void run()
    {
        System.out.println("Hello from Connection Thread!");
        while(!done)
        {
            String host = "myhost";// change accordingly
            String mailStoreType = "imap";
            String username = "myusername";// change accordingly
            String password = "mypasswd";// change accordingly

            check(host, mailStoreType, username, password);

        }
    }

    public static void receiveEmail(String host, String storeType,  String username, String password)
{
    try
    {
        Properties properties = new Properties();  
        properties.put("mail.imap.com", host);  
        properties.put("mail.imap.starttls.enable","true");
        properties.put("mail.imap.auth", "true");  // If you need to authenticate

        // Use the following if you need SSL
        properties.put("mail.imap.socketFactory.port", 993);
        properties.put("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        properties.put("mail.imap.socketFactory.fallback", "false");

        Session emailSession = Session.getDefaultInstance(properties);  
        emailSession.setDebug(true);

        //2) create the IMAP store object and connect with the Imap server  
        IMAPStore emailStore = (IMAPStore) emailSession.getStore(storeType);

        emailStore.connect(host, username, password);  

        //3) create the folder object and open it  
        Folder emailFolder = emailStore.getFolder("INBOX");  
        emailFolder.open(Folder.READ_ONLY);  

        //4) retrieve the messages from the folder in an array and print it  
        Message[] messages = emailFolder.getMessages();  
        for (int i = 0; i <messages.length; i++) 
        {
            Message message = messages[i];  
            MimeMessage m = new MimeMessage(emailSession);
            m.setContent(((MimeMessage)messages[i]).getContent() , "text/plain; charset=UTF-8");
            System.out.println("---------------------------------");  
            System.out.println("Email Number " + (i + 1));  
            System.out.println("Subject: " + message.getSubject());  
            System.out.println("From: " + message.getFrom()[0]);  
            System.out.println("Text: " + message.getContent().toString());  
            m.writeTo(System.out);
        }  

        //5) close the store and folder objects  
        emailFolder.close(false);  
        emailStore.close();  

    } 
    catch (NoSuchProviderException e) {e.printStackTrace();}   
    catch (MessagingException e) {e.printStackTrace();}  
    catch (IOException e) {e.printStackTrace();}

}

    public void stopThread()
    {
        this.done=true;
    }
}

I call the thread from another class like this

connec=new Connection();
 (new Thread(connec)).start();

I get the Following errors:

javax.mail.MessagingException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target;
  nested exception is:
    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:571)
    at javax.mail.Service.connect(Service.java:288)
    at javax.mail.Service.connect(Service.java:169)
    at mailpackage.Connection.check(Connection.java:63)
    at mailpackage.Connection.run(Connection.java:33)
    at java.lang.Thread.run(Thread.java:744)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:882)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
    at com.sun.mail.util.TraceInputStream.read(TraceInputStream.java:110)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
    at com.sun.mail.iap.ResponseInputStream.readResponse(ResponseInputStream.java:98)
    at com.sun.mail.iap.Response.<init>(Response.java:96)
    at com.sun.mail.imap.protocol.IMAPResponse.<init>(IMAPResponse.java:61)
    at com.sun.mail.imap.protocol.IMAPResponse.readResponse(IMAPResponse.java:135)
    at com.sun.mail.imap.protocol.IMAPProtocol.readResponse(IMAPProtocol.java:261)
    at com.sun.mail.iap.Protocol.<init>(Protocol.java:114)
    at com.sun.mail.imap.protocol.IMAPProtocol.<init>(IMAPProtocol.java:104)
    at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:538)
    ... 5 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
    ... 23 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 29 more

i read something about PKIX path error that says to add the cert to java store as a trusted cert, but i dont know if this is the solution for this, and if it is i dont know how to do it.

// i dont have access to the mail server

Any suggestions? thanks!

fnkbz
  • 1,189
  • 1
  • 12
  • 22
  • 4
    I ran into this after installing Avast anti-virus. I found 2 solutions: 1. disable SSL scanning in avast, 2. add your host to "mail.smtp.ssl.trust" in your java mail config. I'm sure neither of these are the recommended approach but they are definitely the easiest options. – pstanton Sep 11 '14 at 22:30
  • The issue is that Sun/Oracle implements its own way of handling certificates and there is no way to specify that you don't want that but want to use e.g. openSSL or the default implementation of your operating system. It's a design issue - or you might even consider it a bug. – Wolfgang Fahl Nov 04 '15 at 07:26

6 Answers6

47

Ok problem solved!

The solution is this:

First get the self-signed certificate from the mail server via openssl:

echo | openssl s_client -connect yoursever:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > yourcert.pem

Then save the yourcert.pem file into this path /Library/Java/Home/lib/security (on macOSX) and put the cert file into the cacerts like this

keytool -keystore cacerts -importcert -alias youralias -file yourcert.pem

The default keystore password is changeit

You can view the change that you made with this command that shows the Certificate fingerprint.

keytool -list -keystore cacerts

After this you should pass these argument in VM

(for windows and linux type yourpath between " " )

-Djavax.net.ssl.trustStore="/Library/Java/Home/lib/security/cacerts"

-Djavax.net.ssl.trustStorePassword="changeit"

For Debug:

-Djava.security.debug=certpath

-Djavax.net.debug=trustmanager

Francesco
  • 4,052
  • 2
  • 21
  • 29
fnkbz
  • 1,189
  • 1
  • 12
  • 22
  • 1
    Note, don't use the quotes if you're putting the VM arguments in eclipse.ini – bcoughlan Feb 17 '15 at 14:17
  • 1
    "After this you should pass these argument in VM" +1 this finally fixed it for me – Amani Kilumanga Mar 24 '16 at 00:32
  • got java.lang.Exception: Input not an X.509 certificate with MacOS while trying to run the command > keytool -keystore cacerts -importcert -alias youralias -file yourcert.pem – Tarun Sep 28 '21 at 18:55
42

You can try upgrade library javax.mail.jar at https://java.net/projects/javamail/pages/Home (now version is 1.5.5) and add code :

MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true); 
properties.put("mail.imap.ssl.trust", "*");
properties.put("mail.imap.ssl.socketFactory", sf);
TungHarry
  • 1,097
  • 11
  • 26
  • 5
    This should be upvoted, simple and avoids all the hecks of storing certificates in the keystore. – Pradyut Bhattacharya Nov 30 '16 at 19:18
  • 7
    I had to replace `imap` with `imaps` in the property values to make this work, but you got my upvote. However, this should only be done for testing! Let the user decide if they trust the server, then add the server to the list of trusted hosts (don't know yet how to do this. When I do, I'll post an answer) – MauganRa Dec 18 '16 at 11:39
  • 3
    This just evades the most essential security feature. Don't do it. – Monkey Supersonic Jun 22 '20 at 07:06
  • Replacing `imap` to `imaps` also worked for me. Thanks! – Vladyslav Pyrozhok Jan 13 '21 at 14:29
  • 3
    seems for SMTP need to replace `mail.imap` to `mail.smtp` – Adir Dayan Apr 19 '21 at 12:31
  • Not working with Java 18 – horvoje Mar 03 '23 at 19:15
  • Sorry about this but I've been trying to find a similar solution but for SMTP not IMAP - How might I alter this solution for SMTP? I'm trying to connect to gmail's SMTP and I get the PKIX error - to which I have no certificate to add to any stores. Any thoughts? Do I just replace "imap" in the property strings above with "smtp" instead? – Seth D. Fulmer Jul 21 '23 at 20:54
6

This JavaMail FAQ entry should help.

Quoted text from the linked site:

Q: When connecting to my mail server over SSL I get an exception like "unable to find valid certification path to requested target".

A: Your server is probably using a test certificate or self-signed certificate instead of a certificate signed by a commercial Certificate Authority. You'll need to install the server's certificate into your trust store. The InstallCert program will help.

Alternatively, you can set the "mail.protocol.ssl.trust" property to the host name of your mail server. See the javadocs for the protocol provider packages for details.

Other common causes of this problem are:

  • There's a firewall or anti-virus program intercepting your request.
  • There's something wrong in your JDK installation preventing it from finding the certificates for the trusted certificate authorities.
  • You're running in an application server that has overridden the JDK's list of trusted certificate authorities.
Community
  • 1
  • 1
Bill Shannon
  • 29,579
  • 6
  • 38
  • 40
  • Thank you it was helpfull! But i am still getting the same error I managed to get the mail server's certificate via openssl.. i imported it into cacert file but when i run the app again i get the same errors – fnkbz Nov 22 '13 at 13:04
  • All I can say is you must be doing something wrong. Without a lot more details of what exactly you did, it's hard to guess what you might've done wrong. – Bill Shannon Nov 22 '13 at 20:37
  • I use MacOSX mavericks. i did the connection to the mail server via terminal with the openssl tool with this command `echo | openssl s_client -connect server:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem` and i save the file in cert.pem. Then i saved the cert.pem file into this path /Library/Java/Home/lib/security and i put the cert file into the cacerts like this `keytool -keystore cacerts -importcert -alias myalias -file cert.pem` then i run the application and i am getting the same errors. Any thoughts? – fnkbz Nov 23 '13 at 23:51
  • Does keytool show you that the cert is there? Is the application running on the same MacOS machine? Do you have more than one version of the JDK or JRE installed on that machine? Is the application being run from the command line using the "java" command, or is it running in an application server? If you turn on extra debugging out as described [here](http://javamail.java.net/docs/SSLNOTES.txt), does it provide any clues? Does it show that it's using the cert you installed? You might want to try the InstallCert program from the FAQ, just in case it makes a difference. – Bill Shannon Nov 24 '13 at 03:53
  • Thanks for the reply! Yes via this command `keytool -list -keystore cacerts` keytool shows the Certificate fingerprint (SHA1). Yes the application runs on the same machine. About the JDK and JRE terminal says `javac version 1.7.0_45` so i dont think that there are installed other versions. I use Eclipse IDE to run the app. If i use these debug options i get a lot of info..i noticed the `subject DNS dont match` and `certs dont match`..i will try to remove the cert and enter it again because i have imported into cacert more than once. thanks for the help the link was very useful! – fnkbz Nov 24 '13 at 17:24
  • I made the changes.. no luck! – fnkbz Nov 24 '13 at 18:21
  • Try running the app outside of Eclipse. – Bill Shannon Nov 25 '13 at 08:11
  • ok i solved the problem i will post the solution..thanks for the hints! – fnkbz Nov 25 '13 at 11:02
  • After importing smtp.gmail.com certificate as **fnkbz** suggested I got the same error. However after I enabled javax.net debugging (`-Djavax.net.debug=all`) I saw text "`Subject: CN=AVG Web/Mail Shield Root, O=AVG Web/Mail Shield, OU=generated by AVG Antivirus for SSL/TLS scanning`" being printed. After disabling AVG everything works as expected. – user435421 Mar 04 '18 at 09:12
  • Thanks a lot, Bill. In my case, I only disabled my antivirus and the program runs, nothing more. You have my vote !!! – Adalberto José Brasaca Aug 04 '20 at 12:43
4

easy way to solve this problem by getiing certificate file from Java 7

copy the "cacerts" file from following java 7 directory

C:\Program Files\Java\jdk1.7.0_79\jre\lib\security

and paste it in java 6 directory

C:\Program Files\Java\jdk1.6.0\jre\lib\security
Baji Shaik
  • 1,022
  • 2
  • 10
  • 14
1

I've lost so many days searching for a solution, and this post was helps to me. I had the same problem. I created a pem file like here, and then, the cert file .pem, was incrusted in cacert file (a copy called TrustStore.jks) with this command:

keytool.exe -import -noprompt -keystore TrustStore.jks -storepass changeit ^ -alias DOMAINNAME -file MYCERTFILE.pem

(DOMAINNAME must be replace by hostname -this trick is very important-, and MYCERTFILE by file recent create...)

I hope that this solution can helps to somebody.

titojusto
  • 11
  • 3
0

I also have run across this problem when talking to a mail server. However, the root cause was that the server (Exchange 2013) had both a real certificate AND a self-signed applied to it. The appropriate course of action was to remove the self-signed on the server because it was taking precedence and blocking the real certificate.

Brian Knoblauch
  • 20,639
  • 15
  • 57
  • 92