Secure Email from Java

Guest Author

I've been working recently with a client to do some rather useful things with notifications, and one of them involved sending a secure email from within a Java program. We encountered some interesting (translation: weird!) challenges, and in overcoming them, I worked out a reasonably straightforward path through the minefield. If you've been thinking about secure-email-enabling your Java app but aren't sure where to start, hopefully this will serve as a fairly quick and mostly painless primer.  :-)

The Problem

Let me first say that if you only want to send a plain-text email from Java, there are ways to do that without much fuss and without any external players. If you want to sign or encrypt your emails, though, you'll need a couple of extra components:
1. a digital certificate (private/public key pair issued by a recognized Certificate Authority, or "CA") and
2. a means of using the certificate to sign and/or encrypt the email

The goal is to digitally sign an email to assure recipients that the sender of the mail is indeed me (or you, if you're following along at work/home). Let's get started!

Getting Your Tools in Order

Getting a Certificate

First, we have to have a digital certificate. If you already have one, you can skip this step...but if not, StartSSL offers free user/email certificates for personal use. Just point your browser to the StartSSL site and click the large button labeled "Sign-up". You'll need to provide them some information, enter the verification code they email to the address you provide, and they do the rest...including installing your new cert and the certificate chain into your web browser.

Freeing the Certificate from your Browser

Perhaps the easiest way to use a certificate is to store it (keys, certificate chain) in a Java Keystore (jks). Extracting your shiny new certificate from your browser is a relatively easy (albeit drawn-out) process. From your browser, export your certificate, including private key. This will produce a .pfx file, which is a PKCS12 keystore. From Chrome, you simply:
  1. Click on the Wrench (or Lines) icon in the upper-right corner
  2. Select "Settings" from the menu
  3. "Show advanced settings..." at the bottom of the page
  4. Scroll down to the section labeled "HTTPS/SSL"
  5. Click the "Manage certificates..." button to display your certificates.
Then, from the certificates window:
  1. Select the target certificate and click the "Export..." button
  2. Click "Next" from the Export Wizard window
  3. Choose "Yes, export the private key" and click "Next"
  4. Under the "Personal Information Exchange - PKCS #12 (.PFX)" entry, select the options to "Include all certificates in the certification path if possible" and "Export all extended properties" (NOTE: Do NOT choose to "Delete the private key if the export is successful". No no no!) and click "Next"
  5. Enter a password (twice) and click "Next"
  6. Provide a path/filename for the export and click "Next", and finally...
  7. Confirm the export options and click "Finish".
Now that we've liberated your cert from the browser, let's make it usable by our (non-browser) Java program.

Creating a Java Keystore

The fastest, easiest way I've found to convert a .pfx file to a .jks (Java Keystore) file is with the Oracle 11g database client. The database client can be downloaded by following this link, selecting the "See All" link to the right of your listed operating system, and choosing the 11g client from the OS-specific download page. Once it's downloaded and installed, you're ready to proceed.

Like the .pfx file, the Oracle wallet is a PKCS12 keystore, and the orapki utility (and other tools) included with the database client can be used to manipulate it...as long as it thinks it's dealing with an Oracle wallet. To make that happen, simply rename the .pfx file to ewallet.p12. Since we aren't dealing with the Oracle Wallet Manager, we don't have to worry about meeting OWM's password criteria or other niceties. Yes, that really is all there is to it!

Now, to make a Java Keystore. To do that, you'll need to open a command prompt and do the following tasks:
  1. Create an ORACLE_HOME environment variable that points to the install location of the Oracle client
  2. Run the following command, pointing to the orapki utility under %ORACLE_HOME%\bin (in Windows) or $ORACLE_HOME/bin (Mac/Linux/UNIX):
orapki wallet pkcs12_to_jks -wallet <wallet_directory> -pwd <wallet_password> -jksKeyStoreLoc <java_key_store_path_and_filename> -jksKeyStorepwd <jks_password>

You should now have a brand new Java KeyStore! You can verify its contents with the OpenSSL keytool utility:
keytool -list -keystore <java_key_store>

Now that we have our credentials in order, on to the Java side of things!

Building the Solution

There are several Java libraries available that aid in signing and/or encrypting email. Of the non-commercial options I found, all use the Bouncy Castle Crypto API and libraries as their underpinnings. Bouncy Castle (BC) may have a funny name, but it's all business with regard to encryption.

At a very high level, you need to do the following things to create/send a signed email:
  1. Provide the email "essentials": SMTP server host & port, email addresses (sender & receiver), a subject, content, and the sending user's password
  2. Add BC as a new crypto provider
  3. Retrieve the cert from your Java Keystore
  4. Create and sign the email using the BC API/libraries
  5. Send the email
There is much more you can do of course, but these are the "must-haves".

In preparation for developing our secure email module, I created a proof of concept (BCCrypTool) by marrying a Java email program I'd written previously and some BC sample code...code reuse at its lowest level, but still good for the environment. :-) What you see here in my GitHub repo is a bit of streamlined Java code that should be pretty easy to repurpose. Please feel free to take a copy and do just that, and if you make significant changes/improvements and are able and inclined to share them, please feel free to do that as well. Sharing is caring.  :-)

A quick note on libraries. You'll need the following to make this work:
And from Bouncy Castle, the following:
  • The BC provider library (bcprov-jdk15on-147.jar)
  • The BC S/MIME library (bcmail-jdk15on-147.jar)
  • The BC security library (bcpkix-jdk15on-147.jar)
There are other BC libraries available here if you'd like to take things even further.

All the best to you in your Java secure email adventures!


Join the discussion

Comments ( 20 )
  • govani Friday, March 1, 2013

    could a java program make my yahoo free web-page-based email able to send encrypted mail to others whom also had the same java code?

  • Mark Heckler Friday, March 1, 2013

    You're actually asking a few questions in there, so let me break them out and try to address each one.

    You can send/receive encrypted emails via Yahoo Mail - using the server/account information in your code - if you know the server name, port, etc.

    Using the web interface to Yahoo Mail (or any web-based email) is a different matter. You could encrypt the text and copy/paste it into the mail message, then the recipient could do the same on the other end. That is similar to how PGP/OpenGPG does it, and while it involves more steps, it's been done reliably for years.

    Underneath most of those options is the concept of PKI, or Public Key Infrastructure. At a really basic level, each person has two keys, one public & one private. As an example, if I encrypt an email to you using your public key, you can decrypt it using your private key (for example). As long as each party has access to the other's public key, it's possible to exchange secure emails.

    I'd recommend reading some books/publications about PKI to get those concepts down, then seeing what is practical within your environment. If both parties are using a webmail interface, OpenGPG (or your own Java-based, stand-alone encryption/decryption program) may be your best bet.

    Hope this helps, and good luck!

    All the best,


  • guest Friday, April 19, 2013


    I would like to ask something regarding java mail. I am reading a mail using java mail api with whih I need to download an attachment from email. Whenever I am looking the mail manually I am able to find the attachment but whenever my code tries to open the mail then it is finding 'winmail.dat' as an attachment rather than Original one. Why it could be happening and what is the reason behind that?

  • Mark Heckler Friday, April 19, 2013


    I haven't run into that particular issue, but I'd encourage you to keep chipping away at it. Updates to JavaMail are mentioned here - http://www.oracle.com/technetwork/java/javamail/index.html - and there is a wealth of information out there on the various combinations of OS, email servers/clients, formats, etc. that can make life "interesting" as a developer. :-)

    I'd also encourage you to share your findings once you isolate and resolve that particular issue. The more we all share, the more we all know.

    All the best,


  • guest Friday, April 26, 2013

    Hi, Sorry for the delay actually I have posted one problem regarding email as a guest as follows.

    I would like to ask something regarding java mail. I am reading a mail using java mail api with whih I need to download an attachment from email. Whenever I am looking the mail manually I am able to find the attachment but whenever my code tries to open the mail then it is finding 'winmail.dat' as an attachment rather than Original one. Why it could be happening and what is the reason behind that?

    I got some R&D on that and came to know something that when a mail is auto forwarded from email clients like Microsoft Outlook or some other things then the attachments are masked as winmail.dat whenever we try to access them technically like using java to download them.

    the file winmail.dat is the file which contains the information about that attachment like attachment link, some style information. Finally I have used a third party jar name 'tnef.jar' to read that file and successfully downloaded the original attachments. :) That jar is works only when the winmail.dat file's content type is 'application/ms-tnef' which generally indicates a file which contains the mail's styles information and attachment information if it has.

    I am very happy to share my knowledge on this thing and also thanking you people for your immediate responses.


  • Mark Heckler Friday, April 26, 2013


    That's great to hear! Congratulations on solving that, and thank you very much for closing the loop and sharing what you found out.

    The Java community is strong and only gets better the more we all share!

    All the best,


  • Roj Sunday, September 8, 2013

    Thanks Mark for this example. Unfortunately I can't seem to get past this error, thought I've followed your instructions here. I'm using NetBeans, getting this error:

    java.io.IOException: Keystore was tampered with, or password was incorrect

    Any hints appreciated! Thanks again.

  • Mark Heckler Monday, September 9, 2013

    Hi Roj,

    Sounds like you may have a misbehaving/corrupt keystore. As a starting point, you might try running

    keytool -list -keystore <java_key_store>

    on the target machine to see if you still have access. If everything checks out and you still get an error, you may want to rename that keystore and create another one, again (best) on that machine.

    Keystores can be a bit temperamental, as you're seeing. Good luck!


  • guest Sunday, September 15, 2013

    Thanks Mark. Yes, I was trying this from a windows7 laptop. I'm going to need to port it to an AIX server anyhow. So I've got the comm. working there, using manual openssl and sendmail. I'm going to try adapting this example there. I'll keep you posted, and thanks!

  • Mark Heckler Monday, September 16, 2013

    Hi Roj,

    You're very welcome! Please do keep me posted; the more we all share, the more we all learn!

    All the best,


  • guest Monday, September 23, 2013

    Hi Mark,

    I have a recipient's public key, and I'd like to use it to encrypt the mime message before it is digitally signed and mailed. I can do this pretty easily with opensssl. Can it be done with your exampke here? I see the dig. signature part, but not the encrption with a public key part? Thanks!

  • Roj Thursday, September 26, 2013

    Can we also encrypt with this example? I have the recipient's public key, would encrypt the signed mime with that. Am I missing thast here? Thanks!

  • Mark Heckler Wednesday, October 2, 2013

    Hi Roj,

    You can do that pretty easily by adding a bit of code to this example to encrypt the message as well. In my code, I only sign it using my key, but for what you need to do you'd want to use the recipient's public key to encrypt it as well.

    I had intended to circle back on this and expand it - quite a bit - by now, but I just haven't had the chance. Soon! Good luck with your efforts, and please share your victories as you go. Security was always an important topic, but it is only becoming more so.

    All the best to you, Roj!


  • Haripriya. Monday, April 20, 2015

    Hi Mark,

    Downlaoded the certificate from StartSSL and generated key store , but still the job failed with this execption .

    javax.mail.MessagingException: Can't send command to SMTP host;

    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.smtp.SMTPTransport.sendCommand(SMTPTransport.java:1307)

    at com.sun.mail.smtp.SMTPTransport.sendCommand(SMTPTransport.java:1295)

    at com.sun.mail.smtp.SMTPTransport.ehlo(SMTPTransport.java:783)

    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:325)

  • Haripriya. Monday, April 20, 2015

    Hi Mark,

    Downloaded the certificate with private key from SSl and converted to java key store, but still seeing this exception while sending out the mail.

    javax.mail.MessagingException: Can't send command to SMTP host; 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

  • Mark Heckler Wednesday, April 22, 2015

    Hi Haripriya,

    This covers it pretty well:


    Basically, it's either a connectivity issue or a trust issue...with the latter being the more likely culprit. Best of luck!

    Hope this helps,


  • Nipuna Thursday, April 23, 2015

    Hi Mark,

    I am trying to run the source code you provided in your GitHub repo. I downloaded below versions of .jar files from BC.




    but it seems the SMIMESignedGenerator.addSigner() method has been made deprecated and the signer.addSigner() call gives error(in Line 130).

    So that I am trying with the addSignerInfoGenerator() method as suggested in API doc. But still could not get it sorted. Do you have any idea on what should be the correct way of calling addSignerInfoGenerator()?

    Highly appreciate your kind support. :)

    Best Regards,


  • Mark Heckler Thursday, April 23, 2015

    Hi Nipuna,

    As you've seen, that code is a bit stale; I haven't done anything with it in two years! I haven't had any reason to return to update things - too many other projects - thus the references to the now-deprecated API.

    Good luck in your efforts, I'm sure you'll crack it!

    All the best,


  • Haripriya. Friday, April 24, 2015

    Thanks Mark. Link you posted was useful , after updating the correct host and the certificate generated by our enterprise resolved the issue.

  • Mark Heckler Friday, April 24, 2015

    Glad to hear it, Haripriya. All the best to you!


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.