I'm not familiar with this function to send mail in java. I'm getting an error while sending email to reset a password. Hope you can give me a solution.
Below is my code:
public synchronized static boolean sendMailAdvance(String emailTo, String subject, String body)
{
String host = AppConfigManager.getProperty("SENDER-EMAIL-SMTP-ADDRESS");
String userName = AppConfigManager.getProperty("SENDER-EMAIL-SMTP-USERNAME");
String password = AppConfigManager.getProperty("SENDER-EMAIL-SMTP-PASSWORD");
String port = AppConfigManager.getProperty("SENDER-EMAIL-SMTP-PORT");
String starttls = AppConfigManager.getProperty("SENDER-EMAIL-SMTP-STARTTLS");
String socketFactoryClass = AppConfigManager.getProperty("SENDER-EMAIL-SMTP-SOCKET-CLASS");
String fallback = AppConfigManager.getProperty("SENDER-EMAIL-SMTP-ALLOW-FALLBACK");
try
{
java.util.Properties props = null;
props = System.getProperties();
props.put("mail.smtp.user", userName);
props.put("mail.smtp.host", host);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.debug", "true");
if(!"".equals(port))
{
props.put("mail.smtp.port", port);
props.put("mail.smtp.socketFactory.port", port);
}
if(!"".equals(starttls))
props.put("mail.smtp.starttls.enable",starttls);
if(!"".equals(socketFactoryClass))
props.put("mail.smtp.socketFactory.class",socketFactoryClass);
if(!"".equals(fallback))
props.put("mail.smtp.socketFactory.fallback", fallback);
Session session = Session.getDefaultInstance(props, null);
session.setDebug(true);
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(userName));
msg.setSubject(subject);
msg.setText(body, "ISO-8859-1");
msg.setSentDate(new Date());
msg.setHeader("content-Type", "text/html;charset=\"ISO-8859-1\"");
msg.addRecipient(Message.RecipientType.TO, new InternetAddress(emailTo));
msg.saveChanges();
Transport transport = session.getTransport("smtp");
transport.connect(host, userName, password);
transport.sendMessage(msg, msg.getAllRecipients());
transport.close();
return true;
}
catch (Exception mex)
{
mex.printStackTrace();
return false;
}
}
Throws the following error:
DEBUG: setDebug: JavaMail version 1.4.1ea-SNAPSHOT
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 465, isSSL false 220 mx.google.com ESMTP m4sm5929870pbg.38 - gsmtp
DEBUG SMTP: connected to host "smtp.gmail.com", port: 465
EHLO fatin
250-mx.google.com at your service, [175.139.198.14]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN
250-ENHANCEDSTATUSCODES
250 CHUNKING
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN"
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Attempt to authenticate
AUTH LOGIN
334 VXNlcm5hbWU6
YWNjb3VudEBibG9vbWluZy5jb20ubXk=
334 UGFzc3dvcmQ6
Ymxvb21pbmc=
535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257
m4sm5929870pbg.38 - gsmtp
[STDOUT] javax.mail.AuthenticationFailedException
[STDOUT] at javax.mail.Service.connect(Service.java:319)
[STDOUT] at javax.mail.Service.connect(Service.java:169)
[STDOUT] at com.vlee.util.mail.SendMail.sendMailAdvance(SendMail.java:283)
[STDOUT] at com.vlee.servlet.ecommerce.DoMemberLogin.fnSendPwd(DoMemberLogin.java:251)
[STDOUT] at com.vlee.servlet.ecommerce.DoMemberLogin.doPost(DoMemberLogin.java:72)
May be this problem cause by Gmail account protection. Just click below link and disable security settings.It will work.
https://www.google.com/settings/security/lesssecureapps
https://www.google.com/settings/security/lesssecureapps
go to your account and turn on the security it will work
You should change the port to 587, I tested your code and it's working fine
If error still happens, please change session variable to code below:
Session session = Session.getInstance(props, new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
});
By default Gmail account is highly secured. When we use gmail smtp from non gmail tool, email is blocked. To test in our local environment, make your gmail account less secure as
Login to Gmail.
Access the URL as https://www.google.com/settings/security/lesssecureapps
Select "Turn on"
Most of AuthenticationFieldException Error occur when sign-in attempted prevented, login your gmail first and go to https://www.google.com/settings/security/lesssecureapps and check turn on. I solved this kind of problem like this way.
If you are logging in to your gmail account from a new application or device, Google might be blocking that device. Try following these steps:
To protect your account, Google might make it harder to sign in to your account if we suspect it isn’t you. For example, Google might ask for additional information besides your username and password if you are traveling or if you try to sign in to your account from a new device.
Go to https://g.co/allowaccess from a different device you have previously used to access your Google account and follow the instructions.
Try signing in again from the blocked app.
Change this (set less secure app):
https://www.google.com/settings/security/lesssecureapps
The solution that works for me has two steps.
First step
package com.student.mail;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
*
* #author jorge santos
*/
public class GoogleMail {
public static void main(String[] args) {
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.socketFactory.port", "465");
props.put("mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "465");
Session session = Session.getDefaultInstance(props,
new javax.mail.Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("conaderindicadores#gmail.com","Silueta95#");
}
});
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("conaderindicadores#gmail.com"));
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse("netneillip#gmail.com"));
message.setSubject("Testing Subject");
message.setText("Test Mail");
Transport.send(message);
System.out.println("Done");
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
}
Enable the gmail security
https://myaccount.google.com/u/2/lesssecureapps?pli=1&pageId=none
There are a few steps you have to keep in mind.
First, make sure you have turned off 2-way authentication of google account
Second, allow access for less secure apps-
https://myaccount.google.com/lesssecureapps
Now there are two scenarios
If you are developing it in your local machine login to your google account in your browser, this way the google recognizes the machine.
If you have deployed the application onto a server then after the first request you will get an authentication error, so you have to give access to the server, just go here to give access- https://www.google.com/accounts/DisplayUnlockCaptcha
I have been getting the same error for long time.
When i changed session debug to true
Session session = Session.getDefaultInstance(props, new GMailAuthenticator("xxxxx#gmail.com", "xxxxx"));
session.setDebug(true);
I got help url https://support.google.com/mail/answer/78754 from console along with javax.mail.AuthenticationFailedException.
From the steps in the link, I followed each steps. When I changed my password with mix of letters, numbers, and symbols to be my surprise the email was generated without authentication exception.
Note: My old password was more less secure.
2 possible reasons:
Your username may require the entire email id 'username#example.com'
Most obvious: The password is wrong. Debug to see if the password being used is correct.
trying to connect to host "smtp.gmail.com", port 465, isSSL false
You got your gmail smtp setting wrong. Gmail requires SSL. Please see tutorials on how to send email via Java via Gmail SMTP, eg: http://www.mkyong.com/java/javamail-api-sending-email-via-gmail-smtp-example/
Just in case anyone comes looking a solution for this problem.
The Authentication problems can be alleviated by activating the google 2-step verification for the account in use and creating an app specific password. I had the same problem as the OP. Enabling 2-step worked.
I had this issue as well but the solution had nothing to do with coding. Make sure you are able to connect to gmail. Ping smtp.gmail.com. If you don't get a reply check your firewall settings. It could also be a proxy setting issue.
Implement Three things with given SMTP settings
Disable two factor aunthentication: https://myaccount.google.com/security
Allow less secure apps : https://www.google.com/settings/security/lesssecureapps
Allow new devices using the link: https://g.co/allowaccess
SMTP Settings:
smtp.gmail.com
Port: 465
Use SSL
From Email Address
Gmail Username
Gmail Password
Recepient Email Address
This is because our application cant bypass 2-step verification. If you are using Gmail then here's a solution.
Click Manage your google account
Go to "Manage your Google Account"
Click Security Menu item
Go into Security Tab and enable 2-Step verification if not already enabled.
Navigate to App passwords
Select a name and generate the password. Copy the 16 letter password before you close the next window.
Select Other
I finally did it. Google doesn't allow third party apps to sign in using your actual password (since March 30th 2022 I think). You have to create an appPassword for your app in gmail. Go to manage accounts in gmail, if you haven't allowed two step verification you'll have to, then the option for creating app password will appear. You'll just type in your app's name and tap the 'generate' button. Your password will popup and you will put it down somewhere. This is the password to be used in the Authentication anonymous class up there in the question.
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
public class SendMail1 {
public static void main(String[] args) {
// Recipient's email ID needs to be mentioned.
String to = "valid email to address";
// Sender's email ID needs to be mentioned
String from = "valid email from address";
// Get system properties
Properties properties = System.getProperties();
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", "smtp.gmail.com");
properties.put("mail.smtp.port", "587");
properties.put("mail.smtp.auth", "true");
Authenticator authenticator = new Authenticator () {
public PasswordAuthentication getPasswordAuthentication(){
return new PasswordAuthentication("userid","password");//userid and password for "from" email address
}
};
Session session = Session.getDefaultInstance( properties , authenticator);
try{
// Create a default MimeMessage object.
MimeMessage message = new MimeMessage(session);
// Set From: header field of the header.
message.setFrom(new InternetAddress(from));
// Set To: header field of the header.
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
// Set Subject: header field
message.setSubject("This is the Subject Line!");
// Now set the actual message
message.setText("This is actual message");
// Send message
Transport.send(message);
System.out.println("Sent message successfully....");
}catch (MessagingException mex) {
mex.printStackTrace();
}
}
}
Related
I am facing an authentication failure issue while trying to connect for both IMAP protocols using the Client Credential Grant flow for OAuth2.0.
Where, I have been following the steps suggested by Microsoft in its step-by-step guide i.e. "Authenticate an IMAP, POP or SMTP connection using OAuth"
I have been using this github project to fetch the Access Token using Client Credential Grant flow:
MSAL Client Credential Grant using Java
Java Code for IMAP
public static void connectIMAP(String userEmail, String accessToken){
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties props= new Properties();
props.put("mail.imap.ssl.enable", "true");
props.put("mail.imap.sasl.enable", "true");
props.put("mail.imap.port", "993");
props.put("mail.imap.auth.mechanisms", "XOAUTH2");
props.put("mail.imap.sasl.mechanisms", "XOAUTH2");
props.put("mail.imap.auth.login.disable", "true");
props.put("mail.imap.auth.plain.disable", "true");
props.setProperty("mail.imap.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.imap.socketFactory.fallback", "false");
props.setProperty("mail.imap.socketFactory.port", "993");
props.setProperty("mail.imap.starttls.enable", "true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true);
try {
final Store store = session.getStore("imap");
store.connect("outlook.office365.com",userEmail, accessToken);
} catch (NoSuchProviderException e) { // session.getStore()
e.printStackTrace();
} catch (MessagingException e) { // store.connect()
e.printStackTrace();
}
}
Following are the credentials I have used while performing the Client Credential Grant flow using MSAL library
userEmail:- Email of the user which is used to login to Azure portal (eg, <registered_azure_email_id>)
authority=https://login.microsoftonline.com/<tenant - id - here>/
client_id=<client(application) - id - here>
IMAGE for app overview screen containing Tenant and Client ID
secret=<client - secret - key - here>
scope=https://outlook.office.com/.default
[Note: I have been using the Default Active Directory, and the default user(Admin)
for my Azure account. Is it fine this way ? or does it require a new custom Azure AD and a
separate tenant for performing client credential flow]
Following image contains list of permissions I have applied in my app:
IMAGE for list of permissions applied
Error Logs:
*** IMAP ***
DEBUG: JavaMail version 1.5.6
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: setDebug: JavaMail version 1.5.6
DEBUG: getProvider() returning javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle]
DEBUG IMAP: mail.imap.fetchsize: 16384
DEBUG IMAP: mail.imap.ignorebodystructuresize: false
DEBUG IMAP: mail.imap.statuscachetimeout: 1000
DEBUG IMAP: mail.imap.appendbuffersize: -1
DEBUG IMAP: mail.imap.minidletime: 10
DEBUG IMAP: enable STARTTLS
DEBUG IMAP: enable SASL
DEBUG IMAP: SASL mechanisms allowed: XOAUTH2
DEBUG IMAP: closeFoldersOnStoreFailure
DEBUG IMAP: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. [UABO......]
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAP: AUTH: PLAIN
DEBUG IMAP: AUTH: XOAUTH2
DEBUG IMAP: protocolConnect login, host=outlook.office365.com, user=ManishPrajapati#SampleOrg2022.onmicrosoft.com, password=<non-null>
DEBUG IMAP: SASL Mechanisms:
DEBUG IMAP: XOAUTH2
DEBUG IMAP:
DEBUG IMAP: SASL client XOAUTH2
DEBUG IMAP: SASL callback length: 2
DEBUG IMAP: SASL callback 0: javax.security.auth.callback.NameCallback#73f9ac
DEBUG IMAP: SASL callback 1: javax.security.auth.callback.PasswordCallback#1064425
A1 AUTHENTICATE XOAUTH2 dXNlcj.....
A1 NO AUTHENTICATE failed.
javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:725)
at javax.mail.Service.connect(Service.java:366)
at javax.mail.Service.connect(Service.java:246)
at test.ClientCredentialGrantAndConnect.connectIMAP(ClientCredentialGrantAndConnect.java:166)
at test.ClientCredentialGrantAndConnect.main(ClientCredentialGrantAndConnect.java:45)
Any help in figuring out the issue will be highly appreciated.
Thank you.
I was able to connect to mailbox using IMAP OAuth2 access token generated by client credential grant. Here are the details:
Java code (Replace clientid, secret, authority and email id in the below code with the values from your azure app registration)
//this method returns the token
public String getAccessTokenByClientCredentialGrant() {
String accessToken = null;
String clientId = "<client id from azure app registration>";
String secret = "<client secret from azure app registration>";
String authority = "https://login.microsoftonline.com/<tenant-id from azure>/oauth2/v2.0/token";
String scope = "https://outlook.office365.com/.default";
log.info("Client ID : "+clientId);
log.info("Client Secret : "+secret);
log.info("Auth Server: "+authority);
log.info("Scope: "+scope);
try {
ConfidentialClientApplication app = ConfidentialClientApplication.builder(
clientId,
ClientCredentialFactory.createFromSecret(secret))
.authority(authority)
.build();
// With client credentials flows the scope is ALWAYS of the shape "resource/.default", as the
// application permissions need to be set statically (in the portal), and then granted by a tenant administrator
ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(
Collections.singleton(scope))
.build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
IAuthenticationResult result = future.get();
accessToken = result.accessToken();
} catch(Exception e) {
log.error("Exception in acquiring token: "+e.getMessage());
e.printStackTrace();
}
log.info("Access Token : "+accessToken);
return accessToken;
}
//This method connects to store using the access token
public Store connect(String userEmailId, String oauth2AccessToken) throws Exception {
String host = "outlook.office365.com";
String port = "993";
Store store = null;
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties props= new Properties();
props.put("mail.imaps.ssl.enable", "true");
props.put("mail.imaps.sasl.enable", "true");
props.put("mail.imaps.port", port);
props.put("mail.imaps.auth.mechanisms", "XOAUTH2");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put("mail.imaps.auth.login.disable", "true");
props.put("mail.imaps.auth.plain.disable", "true");
props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.imaps.socketFactory.fallback", "false");
props.setProperty("mail.imaps.socketFactory.port", port);
props.setProperty("mail.imaps.starttls.enable", "true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true);
store = session.getStore("imaps");
log.info("OAUTH2 IMAP trying to connect with system properties to Host:" + host + ", Port: "+ port
+ ", userEmailId: " + userEmailId+ ", AccessToken: " + oauth2AccessToken);
try {
store.connect(host, userEmailId, oauth2AccessToken);
log.info("IMAP connected with system properties to Host:" + host + ", Port: "+ port
+ ", userEmailId: " + userEmailId+ ", AccessToken: " + oauth2AccessToken);
if(store.isConnected()){
log.info("Connection Established using imap protocol successfully !");
}
} catch (Exception e) {
log.error("Store.Connect failed with the errror: "+e.getMessage());
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
log.error(exceptionAsString);
}
return store;
}
//the main method which calls the above 2 methods.
public void getEmailContents() throws Exception {
Store store = null;
String accessToken = getAccessTokenByClientCredentialGrant();
String emailId = "<email which needs to be read>";
try {
store = connect(emailId, accessToken );
} catch (Exception ex) {
log.error("Exception in connecting to email " + ex.getMessage());
ex.printStackTrace();
}
//write code to read email using javax.mail code
}
Make sure your Application is registered under Azure App Registrations and the following API permissions (Application permissions) are granted in "API Permissions" for the app.
Office 365 Exchange Online
full_access_as_app
IMAP.AccessAsApp
Mail.Read
Mail.ReadWrite
Mail.Send
Also make sure that the mailbox is linked to Azure using the command in the below link:
https://learn.microsoft.com/en-us/graph/auth-limit-mailbox-access
Test-ApplicationAccessPolicy -Identity <email> -AppId <app id>
You can also decode the access token generated from java code using https://jwt.io/ and verify if the permissions are correct.
Verify office365 email configuration and make sure that IMAP is enabled: Help can be found in the below link.
https://www.limilabs.com/blog/office365-enable-imap-pop3-smtp
I am now able to perform the OAuth2.0 authentication for IMAP protocol on exchange-online server.
I found the issue with my approach was that, I was using some parameters from wrong places due to lack of experience on working with Azure.
Following the instructions given in step by step guide and setting permissions of newly created application was OK.
But the real problem was with the queries given at the end of this post where we need to run 3 commands in order to make it possible to perform OAuth2.0
As per my understanding, following is the list of parameters used while performing Service Principal related queries:
Parameters used (and where to find them):
appId: Application (client) ID [ found in Application Overview screen, from both Enterprise and App reg]
entObjId: Object ID(Enterprise app) [ found in Enterprise Application Overview screen only ]
orgId: Directory (tenant) ID [ found in Azure AD overview screen ]
Commands:
New-ServicePrincipal -AppId appId -ServiceId entObjId -Organization orgId
Get-ServicePrincipal -Organization entObjId | fl
Add-MailboxPermission -Identity "<email_id_here>" -User entObjId -AccessRights FullAccess
Confusions I faced:
In Add-MailboxPermission cmdlet, <SERVICE_PRINCIPAL_ID> creates
confusion, because in order to apply permissions like
"IMAP.AccessAsApp", the internet tells that "Service Principal ID"
can be found at [ Azure AD -> Enterprise Application -> (chosen
application) -> Permissions -> IMAP.AccessAsApp -> use the Service
Principal ID from Flyout menu ]
It is okay to use the Enterprise Object ID in all 3 cmdlets
So i am trying to send a pdf through mail using Gmail smtp port 465 but it keeps on throwing this error,
googled it but couldn't solve this.
i don't understand whats wrong? help me on this?
thanks in advance
tried:
1.changing ports
2.tried to correct something on certificates didn't work
error:
Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: Exception reading response;
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.sample.pdf.PDFMailing.pdfMail(PDFMailing.java:72)
at com.sample.pdf.GeneratePdf.addDataToPdf(GeneratePdf.java:42)
at com.sample.pdf.Report.main(Report.java:47)
PDFMailing.java
public static void pdfMail(String file){
//Sender email-ID and Password.
final String senderEmail="xxxxxx";//Sender Mail ID
final String password="xxxxx";//Sender Mail ID Password.
//setting the Properties.
Properties props=new Properties();
props.put("mail.smtp.host", "smtp.gmail.com"); //SMTP Host
props.put("mail.smtp.socketFactory.port", "465"); //SSL Port
props.put("mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory"); //SSL Factory Class
props.put("mail.smtp.auth", "true"); //Enabling SMTP Authentication
props.put("mail.smtp.port", "465"); //SMTP Port
//Authenticating the mailID of the sender.
Authenticator auth = new Authenticator() {
//override the getPasswordAuthentication method
protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
return new javax.mail.PasswordAuthentication(senderEmail, password);
}
};
//Creating and getting the Session Object.
Session session=Session.getInstance(props, auth);
//Setting the From, To, Subject, MessageBody.
try{
Message message=new MimeMessage(session);
message.setFrom(new InternetAddress(senderEmail));//Sender Mail ID
message.setRecipients(Message.RecipientType.TO,InternetAddress.parse("harshapirate#gmail.com"));//Receiver Mail ID
message.setSubject("Sample ECO PDF file");
message.setText("This a Sample ECO PDF file.");
MimeBodyPart bodyPart=new MimeBodyPart();
Multipart multipart=new MimeMultipart();
bodyPart.setText("This is multipart Text.");
//Attachments for any file.
MimeBodyPart pdfAttachment=new MimeBodyPart();
pdfAttachment.attachFile(file);
//Attach the Body part to the Multipart.
multipart.addBodyPart(bodyPart);
multipart.addBodyPart(pdfAttachment);
//Associate multipart to the message.
message.setContent(multipart);
System.out.println("Sending mail is in process.......");
//sending the message to-address mail.
Transport.send(message);
System.out.println("Mail has been sent sucessfully.");
}
catch(Exception e){
throw new RuntimeException(e);
}
}
I presume that is Java 8.0.251. Since you have the latest Java 8 release then this should not be happening:
The root certificates in a 8.0.251 keystore should all be current.
The real smtp.google.com should be using well-known root certificates.
The real smtp.google.com would not be presenting the cert chain in the wrong order.
So I think that something is else "getting in the way". Likely explanations include:
Something that is sending outgoing email connections through an SMTP proxy; e.g. a firewall or anti-virus product.
You are running on an application server that has overridden the set of trusted certificates provided by the JDK.
It is also possible that something has subverted your DNS or IP routing and you are talking to a spoofed "smtp.gmail.com" server.
Check the following:
Check if latest JDK is installed (Command: java -version) so that it has latest
certificates and updated CA's.
Check if there are multiple JDKs or JREs installed: If so remove them.
Check if JAVA_HOME is pointing to the latest JDK you installed.
(Command: echo $JAVA_HOME in linux Or echo %JAVA_HOME% in Windows command prompt)
Check if your system date and time are correct.
If above is verified then your Java installation is fine.
Code:
I see a missing property in your code: props.put("mail.smtp.starttls.enable", "true").
Add it and try.
Hope you are able to access Gmail from your browser at least. This confirms that your machine is able to access Gmail servers - Though not an exact test for SMTP, but it is still good to test.
If you are running inside Tomcat, then ensure you have the latest version and hope it has its certificate store not customized or altered in some way.
If everything above is OK, then either you are behind some proxy or you are hacked.
Maybe check for a system property or other way that someone has defined a different trust store e.g. with: -Djavax.net.ssl.trustStore=somefilename.jks
See: https://www.baeldung.com/java-keystore-truststore-difference
But the default truststore should be $JAVA_HOME/jre/lib/security/cacerts (but its contents vary between the Oracle JDK and OpenJDK - this was later fixed, see: https://openjdk.java.net/jeps/319 )
Inspecting/modifying the contents of the store can be done with the command line tool: keytool or a GUI like: https://keystore-explorer.org/
Before you go crazy try starting your application with the following extra System Property for java (-Dsystempropertyname=value):
-Djavax.net.debug=all
Then you will exactly see all details of the used trust store and offered certificates from the server, details of the SSL/TLS handshake and even all data encrypted/decrypted.
For all the information there is on this subject see the JSSE Reference Guide for your Java version, e.g.: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html
The same kind of code, I have written earlier and is in working state. Could you please give a try on using this code below:
Also, check the proper version of Java installed 8+ in your system, with all the Environment variables properly set and required for your project. If any proxy settings exists in your system, try to remove it and then again running the code.
//this will work only for gmail.
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import com.[MyProjectRelatedImports].pojo.EmployeeDetails;
public class SendEmail {
public static void sendMail(List<EmployeeDetails> emplDetails) {
Address[] to = new Address[emplDetails.size()];
try {
for (int i = 0; i < to.length; i++) {
to[i] = new InternetAddress(emplDetails.get(i).getEmail());
}
} catch (MessagingException e) {
e.printStackTrace();
}
// Recipient's email ID needs to be mentioned.
String tom = "xyz#gmail.com";// address of recipient
// Sender's email ID needs to be mentioned
String from = "abc#gmail.com"; //address of sender
// Assuming you are sending email from localhost
String host = "smtp.gmail.com";
// Get system properties
Properties properties = System.getProperties();
// Setup mail server
properties.setProperty("mail.smtp.host", host);
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.user", "emailID"); // User name
properties.put("mail.smtp.password", "password"); // password
properties.put("mail.smtp.port", "587");// default mail submission port
properties.put("mail.smtp.auth", "true");
// Get the default Session object.
Session session = Session.getDefaultInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("emailID", "password"); // username will be your email address and password same as your Gmail account.
// And if your account is protected with 2 step verification then you need to generate the app password from the link provided
//https://security.google.com/settings/security/apppasswords
}
});
try {
// Create a default MimeMessage object.
MimeMessage message = new MimeMessage(session);
// Set From: header field of the header.
message.setFrom(new InternetAddress(from));
// Set To: header field of the header. //message.addRecipient(Message.RecipientType.TO, new InternetAddress(tom));
//Send Email to multiple recipients
message.addRecipients(Message.RecipientType.TO, to);
// Set Subject: header field
message.setSubject("Subject text via Java Class");
// Now set the actual message
message.setText("Message Content should be written here!!! Regards: Pratishtha Sharma ");
// Send message
Transport.send(message);
System.out.println("Sent message successfully....");
} catch (MessagingException mEx){
mEx.printStackTrace();}
}
}
I'm trying to send an email via java.mail SMTP. I have 2 mail accounts using the same provider and settings:
using a short password with no special characters
using a long password with special characters (* > / % !)
The first one works. The second one says 535 Authentication credentials invalid.
I'm using java.mail 1.5.
Here's my code:
Properties props = new Properties();
props.put("mail.smtps.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", "smtp.1und1.de");
props.put("mail.smtp.port", "465");
Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("foo#example.org", "$§$&/&%§$!><>");
}
});
Transport transport = session.getTransport("smtps");
transport.connect("smtp.1und1.de", username, password);
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("foo#example.org"));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("bar#example.org"));
message.setSubject("subject");
message.setText("text");
transport.sendMessage(message, message.getAllRecipients());
Do I need to encode the password somehow?
Thanks in advance.
EDIT:
I now tried to login via telnet. Same problem. So this isn't related to Java, but it may be some common SMTP issue.
Using the E-Mail account using Apple Mail on Mac and iPhone works without any issues.
If you have non-ASCII special characters, you'll need to use JavaMail 1.6 and set the mail.mime.allowutf8 Session property. And the server needs to support the SMTPUTF8 extension.
I have been trying to send an email using an smtp server through javamail api. I get the following error:
javax.mail.MessagingException: Could not connect to SMTP host: smtp.host.com, port: 587;
nested exception is:java.net.SocketException: Permission denied: connect
Here's how I create the Properties and Session object for the mail:
private Session getSession() {
Authenticator authenticator = new Authenticator();
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.submitter", authenticator.getPasswordAuthentication().getUserName());
properties.setProperty("mail.smtp.auth", "false");
properties.setProperty("mail.smtp.starttls.enable", "false");
properties.setProperty("mail.smtp.host", "smtp.hostname.com");
properties.setProperty("mail.smtp.port", "587");
properties.setProperty("mail.smtp.ssl.trust", "smtp.hostname.com");
properties.setProperty("java.net.preferIPv4Stack" , "true");
return Session.getInstance(properties, authenticator);
}
private class Authenticator extends javax.mail.Authenticator {
private PasswordAuthentication authentication;
public Authenticator() {
String username = "username";
String password = "password";
authentication = new PasswordAuthentication(username, password);
}
protected PasswordAuthentication getPasswordAuthentication() {
return authentication;
}
}
I have tried disabling the authentication as suggested by some posts and also put in resolutions for IPv4 preference according to this post:
JavaMail API to iMail -- java.net.SocketException: Permission denied: connect
but I still get the same error. Is there any other way this issue might be resolved?
Thanks.
I found a similar problem here.
Try to see if the problem is relate to an anti virus or a firewall blocking your requests.
Switch off you firewall and find in Google some security certificate that missed in you jar/lib/security
I have already faced this then I have to make use phpmailer lib in php and make on API use anywhere in your code so you can try php.
I have created an email account for admin of my web site using google's gmail app as admin#mywebsite.com. I am able to login using the credentials on gmail's login web page.
Now i want to send email using java and this id
String host = "smtp.gmail.com";
String from = "admin#mywebsite.com";
String pass = "myPass";
Properties props = System.getProperties();
props.put("mail.smtp.starttls.enable", "true"); // added this line
props.put("mail.smtp.host", host);
props.put("mail.smtp.user", from);
props.put("mail.smtp.password", pass);
....
...
...
Session session = Session.getDefaultInstance(props, auth);
...
...
Transport transport = session.getTransport("smtp");
transport.connect(host, from, pass);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
This is throwing an exception as
Exception in thread "main" javax.mail.AuthenticationFailedException
However, when i try this with gmail credentials (myid#gmail.com), it works.
Please help me out on this. Thanks in advance
Judging by the accepted answer to What mechanism does Gmail use for user authentication?, you need to connect to Google's mail server on port 465 or 587, then use STARTTLS (presumably only on port 587) and user authentication. So what you are lacking is the port 465 or 587 part.
Have you already authenticated your admin#mywebsite.com with Send As permissions in your gmail Account Settings?
If yes, then you might need to give your authentication user id and password as your gmail account.
you have to used for port number to connect with gmail.
TLS:587
SSL:465
you have to used one of them so you can send the email through gmail.