Fall back to HELO command if the server doesn't know EHLO (SMTP)
Fixes issue 2704
This commit is contained in:
parent
3c5a63adeb
commit
d848b434f5
1 changed files with 84 additions and 13 deletions
|
@ -288,20 +288,11 @@ public class SmtpTransport extends Transport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> results = executeSimpleCommand("EHLO " + localHost);
|
List<String> results = sendHello(localHost);
|
||||||
|
|
||||||
m8bitEncodingAllowed = results.contains("8BITMIME");
|
m8bitEncodingAllowed = results.contains("8BITMIME");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO may need to add code to fall back to HELO I switched it from
|
|
||||||
* using HELO on non STARTTLS connections because of AOL's mail
|
|
||||||
* server. It won't let you use AUTH without EHLO.
|
|
||||||
* We should really be paying more attention to the capabilities
|
|
||||||
* and only attempting auth if it's available, and warning the user
|
|
||||||
* if not.
|
|
||||||
*/
|
|
||||||
if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL
|
if (mConnectionSecurity == CONNECTION_SECURITY_TLS_OPTIONAL
|
||||||
|| mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
|
|| mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
|
||||||
if (results.contains("STARTTLS")) {
|
if (results.contains("STARTTLS")) {
|
||||||
|
@ -322,7 +313,7 @@ public class SmtpTransport extends Transport {
|
||||||
* Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically,
|
* Now resend the EHLO. Required by RFC2487 Sec. 5.2, and more specifically,
|
||||||
* Exim.
|
* Exim.
|
||||||
*/
|
*/
|
||||||
results = executeSimpleCommand("EHLO " + localHost);
|
results = sendHello(localHost);
|
||||||
} else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
|
} else if (mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED) {
|
||||||
throw new MessagingException("TLS not supported but required");
|
throw new MessagingException("TLS not supported but required");
|
||||||
}
|
}
|
||||||
|
@ -408,6 +399,46 @@ public class SmtpTransport extends Transport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the client "identity" using the EHLO or HELO command.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* We first try the EHLO command. If the server sends a negative response, it probably doesn't
|
||||||
|
* support the EHLO command. So we try the older HELO command that all servers need to support.
|
||||||
|
* And if that fails, too, we pretend everything is fine and continue unimpressed.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param host
|
||||||
|
* The EHLO/HELO parameter as defined by the RFC.
|
||||||
|
*
|
||||||
|
* @return The list of capabilities as returned by the EHLO command or an empty list.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* In case of a network error.
|
||||||
|
* @throws MessagingException
|
||||||
|
* In case of a malformed response.
|
||||||
|
*/
|
||||||
|
private List<String> sendHello(String host) throws IOException, MessagingException {
|
||||||
|
try {
|
||||||
|
//TODO: We currently assume the extension keywords returned by the server are always
|
||||||
|
// uppercased. But the RFC allows mixed-case keywords!
|
||||||
|
|
||||||
|
return executeSimpleCommand("EHLO " + host);
|
||||||
|
} catch (NegativeSmtpReplyException e) {
|
||||||
|
if (K9.DEBUG) {
|
||||||
|
Log.v(K9.LOG_TAG, "Server doesn't support the EHLO command. Trying HELO...");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
executeSimpleCommand("HELO " + host);
|
||||||
|
} catch (NegativeSmtpReplyException e2) {
|
||||||
|
Log.w(K9.LOG_TAG, "Server doesn't support the HELO command. Continuing anyway.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<String>(0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(Message message) throws MessagingException {
|
public void sendMessage(Message message) throws MessagingException {
|
||||||
ArrayList<Address> addresses = new ArrayList<Address>();
|
ArrayList<Address> addresses = new ArrayList<Address>();
|
||||||
|
@ -570,12 +601,28 @@ public class SmtpTransport extends Transport {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkLine(String line) throws MessagingException {
|
private void checkLine(String line) throws MessagingException {
|
||||||
if (line.length() < 1) {
|
int length = line.length();
|
||||||
|
if (length < 1) {
|
||||||
throw new MessagingException("SMTP response is 0 length");
|
throw new MessagingException("SMTP response is 0 length");
|
||||||
}
|
}
|
||||||
|
|
||||||
char c = line.charAt(0);
|
char c = line.charAt(0);
|
||||||
if ((c == '4') || (c == '5')) {
|
if ((c == '4') || (c == '5')) {
|
||||||
throw new MessagingException(line);
|
int replyCode = -1;
|
||||||
|
String message = line;
|
||||||
|
if (length >= 3) {
|
||||||
|
try {
|
||||||
|
replyCode = Integer.parseInt(line.substring(0, 3));
|
||||||
|
} catch (NumberFormatException e) { /* ignore */ }
|
||||||
|
|
||||||
|
if (length > 4) {
|
||||||
|
message = line.substring(4);
|
||||||
|
} else {
|
||||||
|
message = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NegativeSmtpReplyException(replyCode, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,4 +727,28 @@ public class SmtpTransport extends Transport {
|
||||||
throw new AuthenticationFailedException("Unable to negotiate MD5 CRAM");
|
throw new AuthenticationFailedException("Unable to negotiate MD5 CRAM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception that is thrown when the server sends a negative reply (reply codes 4xx or 5xx).
|
||||||
|
*/
|
||||||
|
static class NegativeSmtpReplyException extends MessagingException {
|
||||||
|
private static final long serialVersionUID = 8696043577357897135L;
|
||||||
|
|
||||||
|
private final int mReplyCode;
|
||||||
|
private final String mReplyText;
|
||||||
|
|
||||||
|
public NegativeSmtpReplyException(int replyCode, String replyText) {
|
||||||
|
super("Negative SMTP reply: " + replyCode + " " + replyText);
|
||||||
|
mReplyCode = replyCode;
|
||||||
|
mReplyText = replyText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReplyCode() {
|
||||||
|
return mReplyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReplyText() {
|
||||||
|
return mReplyText;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue