Good evening SO
I'm trying to make wonderful piece of code that can retrieve message over the POP protocol. I've so far followed the RFC1939 (POP Specification).
And actually it's working with my web host's POP3 server (which is not over SSL).But when accessing GMail all I get is empty responses :(
I assume it's the SSL part that's "breaking" it.
In my "open" function that creates the Socket I have this:
public void open() throws UnknownHostException, IOException
{
if(this.SSL)
{
SSLSocketFactory fac = (SSLSocketFactory) SSLSocketFactory.getDefault();
this.s = fac.createSocket(this.in_host, this.in_port);
}
else
{
this.s = new Socket(this.in_host, this.in_port);
}
this.out = new PrintWriter(s.getOutputStream(), true);
this.in = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
where SSL is a bool indicating the connection should be over SSL, and s is the Socket. in_host and in_port is the host (pop.gmail.com) and port (995). out and in is the streams I write and read to/from.
One of the worst parts is that it doensn't throw any errors. Where I normally get the response, I just get an empty string.
Question is: How do I connect to a POP server over SSL/TLS, preferably the Gmail server?
What about something like this:
public void connect() throws Exception {
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties pop3Props = new Properties();
pop3Props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
pop3Props.setProperty("mail.pop3.socketFactory.fallback", "false");
pop3Props.setProperty("mail.pop3.port", "995");
pop3Props.setProperty("mail.pop3.socketFactory.port", "995");
URLName url = new URLName("pop3", "pop.gmail.com", 995, "",
username, password);
session = Session.getInstance(pop3Props, null);
store = new POP3SSLStore(session, url);
store.connect();
}
See this article for more info.
declare socket s as SSLSocket . Then it will work
Related
I am trying to implement email reading in java for gmail. I am mostly concerned with pop3 and smtp connections. I have successfully implemented the functionality for smtp but I am facing continuous connection refused errors when using pop3. Below is the minimal example.
public class ReadEmailStep {
public static void main(String[] args) {
// for smtp
// String host = "smtp.gmail.com";// change accordingly
// String mailStoreType = "imaps";
// for pop3
String host = "pop.gmail.com";
String mailStoreType = "pop3s";
String username = "<email_address>";// change accordingly
String password = "<password>";// change accordingly
String folder = "INBOX";
readMessages(host, mailStoreType, username, password, folder);
}
private static void addPop3Props(Properties properties, String host, String port) {
properties.setProperty("mail.pop3.host", host);
properties.setProperty("mail.pop3.port", port);
properties.setProperty("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.setProperty("mail.pop3.socketFactory.port", port);
properties.setProperty("mail.pop3.starttls.enable", "true");
properties.setProperty("mail.pop3.socketFactory.fallback", "false");
properties.setProperty("mail.pop3.rsetbeforequit", "true");
}
private static void addSmtpProps(Properties properties, String host, String port) {
properties.setProperty("mail.smtp.host", host);
properties.setProperty("mail.smtp.socketFactory.port", port);
properties.setProperty("mail.smtp.port", port);
properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.setProperty("mail.smtp.auth", "true");
}
public static void readMessages(String host, String storeType, String user, String password, String folder) {
try {
// create properties field
Properties properties = new Properties();
if (storeType.equals("pop3s")) {
addPop3Props(properties, host, "995");
} else if (storeType.equals("imaps")){
addSmtpProps(properties, host, "465");
} else {
throw new Exception("unknown storeType: " + storeType);
}
URLName url = new URLName(storeType, host, 995, "", user, password);
Session session = Session.getInstance(properties, null);
Store store = new POP3SSLStore(session, url);
store.connect();
//Session emailSession = Session.getDefaultInstance(properties, null);
//Store store = emailSession.getStore(storeType);
store.connect(host, user, password);
// create the folder object and open it
Folder emailFolder = store.getFolder(folder);
emailFolder.open(Folder.READ_ONLY);
// retrieve the messages from the folder in an array and print it
Message[] messages = emailFolder.getMessages();
System.out.println("messages.length---" + messages.length);
// do something with messages
// close the store and folder objects
emailFolder.close(false);
store.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Following is the stacktrace I am getting;
javax.mail.MessagingException: Connect failed;
nested exception is:
java.net.ConnectException: Connection refused: connect
at com.sun.mail.pop3.POP3Store.protocolConnect(POP3Store.java:120)
at javax.mail.Service.connect(Service.java:233)
at javax.mail.Service.connect(Service.java:134)
at javax.mail.Service.connect(Service.java:86)
at com.smartstream.control.engine.custom.ReadEmailStep.readMessages(ReadEmailStep.java:71)
at com.smartstream.control.engine.custom.ReadEmailStep.main(ReadEmailStep.java:32)
I have already referred to following threads but none of them has helped.
Connecting to POP3 with gmail fails
https://www.java-tips.org/other-api-tips-100035/61-javamail/2450-connecting-gmail-using-pop3-connection-with-ssl.html
Thanks.
I use code from this link to access gmail imap server, because I could not find Android-friendly port of javamail with OAUTH support (javamail 1.5.2 or higher).
However, the problem with this code:
public static IMAPStore connectToImap(String host, int port, String userEmail, String oauthToken, boolean debug) throws Exception {
Properties props = new Properties();
props.put("mail.imaps.sasl.enable", "true");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
Session session = Session.getInstance(props);
session.setDebug(debug);
final URLName unusedUrlName = null;
IMAPSSLStore store = new IMAPSSLStore(session, unusedUrlName);
final String emptyPassword = "";
store.connect(host, port, userEmail, emptyPassword);
return store;
}
is that a new Store object is created every time auth token is changed (expires). And then I have to create a new Folder and read my messages again...
My question is:
Is it possible to change auth token without creating a new Store object? I would like to be able to implement something like
store.connect("imap.gmail.com", username, oauth2_access_token)
(example from javamail 1.5.2) to reconnect, without the need to recreate the Store object.
Thank you very much!
If you need to create a new connection with the same Store you should be able to set the property to a new value and make a new connection, without creating a new Store object. Just call props.put with the new value. The Session keeps a reference to the Properties object rather than making a copy of it.
I need some help with implementing a manual ssl handshake between an android smartphone and a server.
The background why is in my case the encryption/decryption of the communication. Android would be just a proxy which should have no information about what data is exchanged between the server and my javacard applet which only can communicate with the android device.
My first thought was to establich a connection to a server like a normal http just on the ssl port of the server: (in android)
Socket socket = new Socket("google.de", 443);
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
DataInputStream is = new DataInputStream(socket.getInputStream());
// send data for the handshake
os.writeChars("Params for the SSL handshake");
// read the server response
in.read(...)
// answer with the next ssl handshake step
....
and then send the information for the handshake and wait for the response.
Problem here is, I don't know in which format I would have to send the parameters (like the client hello: protocolVersion, random, sessionID, cipherSuites, compressMethod). Or if it would work?
The other way I inspected was the
javax.net.ssl.SSLSocket;
which makes the handshake by itself.
For example:
public static void main(final String[] args) throws Exception {
final SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, null, null);
// getDefault();
final SSLSocketFactory fac = sslContext.getSocketFactory();
final SSLSocket socket = (SSLSocket) fac.createSocket("google.de", 443);
socket.addHandshakeCompletedListener(new HandshakeCompletedListener() {
#Override
public void handshakeCompleted(final HandshakeCompletedEvent event) {
System.out.println("Cipher:" + event.getCipherSuite());
}
});
final String[] ciphers = fac.getSupportedCipherSuites();
final String[] protocols = { "TLSv1" };
final SSLParameters params = new SSLParameters(ciphers, protocols);
params.setNeedClientAuth(false);
socket.setSSLParameters(params);
socket.startHandshake();
}
In this case, all the relevant security information (like the secret exchange) and so on will happen on Android... (in detail: in the SSLSocket itself I think) That's exactly the way I don't want!
I want to have the possibility to send the handshake parameters by my own to the server and can catch the response from the server and will forward it to my javacard applet. I know I have to take care of the encryption later on by myself.
I hope my problem is understandable and the background why I need this too. Else please give a small hint and I will do my best to complete the information.
Thanks in advance!
I want to create my DbxRequestConfig Object with a StandardHttpRequestor, because I need it to use a Proxy.
The Proxy is a http Proxy, Port 80, and needs authentication.
Proxyaddress: http://myproxy.com
Proxyport: 80
Proxyusername: username
Proxypassword: password
So I tried to use the global Java Proxy setup:
System.setProperty("http.proxy","proxyaddress") //... http.proxyUser, http.ProxyPassword
//and so on
It did not work.
After looking into the StandardHttpRequestor I realized I need to use this Object as well as a Proyx Object:
Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(ip,port));
StandardHttpRequestor requ = new StandardHttpRequestor(proxy);
Which is wrong, because it has no authentication.
For authentication, the net and google show me the following. Putting all together, my current code looks like the following:
String ip = "http://myproxy.com";
int port = 80;
final String authUser = "username";
final String authPassword = "password";
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(authUser, authPassword.toCharArray());
}
});
System.setProperty("http.proxyUser", authUser);
System.setProperty("http.proxyPassword", authPassword);
Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(ip,port));
StandardHttpRequestor requ = new StandardHttpRequestor(proxy);
return requ;
But this does not work as well.
What am I doing wrong?
I can't seem to get the Proxy to work.
One problem was the http:// in String ip = "http://myproxy.com";
My current code looks the following, and works sometimes. Sometimes not. I have no idea why. Sometimes I have to reallow the App to be connected to my DropBox Account, because the authKey doesn't come through the proxy...
Well at least I got an example working for you guys having the same trouble. Maybe the rest of the problem is on the proxy side? I'll have a further look into this. But here comes my code:
public HttpRequestor getProxy(){
if("true".equals(config.getProperty("proxy","false"))){
String ip = "proxy.myproxy.com";
int port = 80;
final String authUser = "username";
final String authPassword = "password";
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(authUser, authPassword.toCharArray());
}
});
Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress(ip,port));
HttpRequestor req = new StandardHttpRequestor(proxy);
return req;
}
return null;
}
As you can see I don't use the StandardHttpRequestor anymore. For the Dropbox code it is the following:
HttpRequestor requ = con.getProxy();
if(requ!=null)
config = new DbxRequestConfig(APP_NAME, Locale.getDefault().toString(),requ);
else
config = new DbxRequestConfig(APP_NAME, Locale.getDefault().toString());
As I already said, sometimes it works. Sometimes not. I'm going to write more info about that as soon as I know if it's because of the code or because of the proxy itself.
I have been trying to use a custom SocketFactory in the httpclient library from the Apache HTTPComponents project. So far without luck. I was expecting that I could just set a socket factory for a HttpClient instance, but it is obviously not so easy.
The documentation for HttpComponents at http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html does mention socket factories, but does not say how to use them.
Does anybody know how this is done?
oleg's answer is of course correct, I just wanted to put the information directly here, in case the link goes bad. In the code that creates a HttpClient, I use this code to let it use my socket factory:
CustomSocketFactory socketFactory = new CustomSocketFactory();
Scheme scheme = new Scheme("http", 80, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(scheme);
CustomSocketFactory is my own socket factory, and I want to use it for normal HTTP traffic, that's why I use "http" and 80 as parameters.
My CustomSchemeSocketFactory looks similar to this:
public class CustomSchemeSocketFactory implements SchemeSocketFactory {
#Override
public Socket connectSocket( Socket socket, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpParams params ) throws IOException, UnknownHostException, ConnectTimeoutException {
if (localAddress != null) {
socket.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
socket.bind(localAddress);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
try {
socket.setSoTimeout(soTimeout);
socket.connect(remoteAddress, connTimeout );
} catch (SocketTimeoutException ex) {
throw new ConnectTimeoutException("Connect to " + remoteAddress + " timed out");
}
return socket;
}
#Override
public Socket createSocket( HttpParams params ) throws IOException {
// create my own socket and return it
}
#Override
public boolean isSecure( Socket socket ) throws IllegalArgumentException {
return false;
}
}
We use a custom socket factory to allow HttpClient connections to connect to HTTPS URLs with untrusted certificates.
Here is how we did it:
We adapted implementations of both the 'EasySSLProtocolSocketFactory' and 'EasyX509TrustManager' classes from the examples source directory referenced by Oleg.
In our HttpClient startup code, we do the following to enable the new socket factory:
HttpClient httpClient = new HttpClient();
Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", easyhttps);
So that any time we request an https:// URL, this socket factory is used.