📄 smtptransport.java
字号:
try {
closeConnection();
} catch (MessagingException mex) { } // ignore it
}
///////////////////// smtp stuff ///////////////////////
private BufferedInputStream serverInput;
private LineInputStream lineInputStream;
private OutputStream serverOutput;
private Socket serverSocket;
/////// smtp protocol //////
/**
* Issue the <code>HELO</code> command.
*
* @param domain our domain
*
* @since JavaMail 1.4.1
*/
protected void helo(String domain) throws MessagingException {
if (domain != null)
issueCommand("HELO " + domain, 250);
else
issueCommand("HELO", 250);
}
/**
* Issue the <code>EHLO</code> command.
* Collect the returned list of service extensions.
*
* @param domain our domain
* @return true if command succeeds
*
* @since JavaMail 1.4.1
*/
protected boolean ehlo(String domain) throws MessagingException {
String cmd;
if (domain != null)
cmd = "EHLO " + domain;
else
cmd = "EHLO";
sendCommand(cmd);
int resp = readServerResponse();
if (resp == 250) {
// extract the supported service extensions
BufferedReader rd =
new BufferedReader(new StringReader(lastServerResponse));
String line;
extMap = new Hashtable();
try {
boolean first = true;
while ((line = rd.readLine()) != null) {
if (first) { // skip first line which is the greeting
first = false;
continue;
}
if (line.length() < 5)
continue; // shouldn't happen
line = line.substring(4); // skip response code
int i = line.indexOf(' ');
String arg = "";
if (i > 0) {
arg = line.substring(i + 1);
line = line.substring(0, i);
}
if (debug)
out.println("DEBUG SMTP: Found extension \"" +
line + "\", arg \"" + arg + "\"");
extMap.put(line.toUpperCase(Locale.ENGLISH), arg);
}
} catch (IOException ex) { } // can't happen
}
return resp == 250;
}
/**
* Issue the <code>MAIL FROM:</code> command to start sending a message. <p>
*
* Gets the sender's address in the following order:
* <ol>
* <li>SMTPMessage.getEnvelopeFrom()</li>
* <li>mail.smtp.from property</li>
* <li>From: header in the message</li>
* <li>System username using the
* InternetAddress.getLocalAddress() method</li>
* </ol>
*
* @since JavaMail 1.4.1
*/
protected void mailFrom() throws MessagingException {
String from = null;
if (message instanceof SMTPMessage)
from = ((SMTPMessage)message).getEnvelopeFrom();
if (from == null || from.length() <= 0)
from = session.getProperty("mail." + name + ".from");
if (from == null || from.length() <= 0) {
Address[] fa;
Address me;
if (message != null && (fa = message.getFrom()) != null &&
fa.length > 0)
me = fa[0];
else
me = InternetAddress.getLocalAddress(session);
if (me != null)
from = ((InternetAddress)me).getAddress();
else
throw new MessagingException(
"can't determine local email address");
}
String cmd = "MAIL FROM:" + normalizeAddress(from);
// request delivery status notification?
if (supportsExtension("DSN")) {
String ret = null;
if (message instanceof SMTPMessage)
ret = ((SMTPMessage)message).getDSNRet();
if (ret == null)
ret = session.getProperty("mail." + name + ".dsn.ret");
// XXX - check for legal syntax?
if (ret != null)
cmd += " RET=" + ret;
}
/*
* If an RFC 2554 submitter has been specified, and the server
* supports the AUTH extension, include the AUTH= element on
* the MAIL FROM command.
*/
if (supportsExtension("AUTH")) {
String submitter = null;
if (message instanceof SMTPMessage)
submitter = ((SMTPMessage)message).getSubmitter();
if (submitter == null)
submitter = session.getProperty("mail." + name + ".submitter");
// XXX - check for legal syntax?
if (submitter != null) {
try {
String s = xtext(submitter);
cmd += " AUTH=" + s;
} catch (IllegalArgumentException ex) {
if (debug)
out.println("DEBUG SMTP: ignoring invalid submitter: " +
submitter + ", Exception: " + ex);
}
}
}
/*
* Have any extensions to the MAIL command been specified?
*/
String ext = null;
if (message instanceof SMTPMessage)
ext = ((SMTPMessage)message).getMailExtension();
if (ext == null)
ext = session.getProperty("mail." + name + ".mailextension");
if (ext != null && ext.length() > 0)
cmd += " " + ext;
issueSendCommand(cmd, 250);
}
/**
* Sends each address to the SMTP host using the <code>RCPT TO:</code>
* command and copies the address either into
* the validSentAddr or invalidAddr arrays.
* Sets the <code>sendFailed</code>
* flag to true if any addresses failed.
*
* @since JavaMail 1.4.1
*/
/*
* success/failure/error possibilities from the RCPT command
* from rfc821, section 4.3
* S: 250, 251
* F: 550, 551, 552, 553, 450, 451, 452
* E: 500, 501, 503, 421
*
* and how we map the above error/failure conditions to valid/invalid
* address vectors that are reported in the thrown exception:
* invalid addr: 550, 501, 503, 551, 553
* valid addr: 552 (quota), 450, 451, 452 (quota), 421 (srvr abort)
*/
protected void rcptTo() throws MessagingException {
Vector valid = new Vector();
Vector validUnsent = new Vector();
Vector invalid = new Vector();
int retCode = -1;
MessagingException mex = null;
boolean sendFailed = false;
MessagingException sfex = null;
validSentAddr = validUnsentAddr = invalidAddr = null;
boolean sendPartial = false;
if (message instanceof SMTPMessage)
sendPartial = ((SMTPMessage)message).getSendPartial();
if (!sendPartial) {
String sp = session.getProperty("mail." + name + ".sendpartial");
sendPartial = sp != null && sp.equalsIgnoreCase("true");
}
if (debug && sendPartial)
out.println("DEBUG SMTP: sendPartial set");
boolean dsn = false;
String notify = null;
if (supportsExtension("DSN")) {
if (message instanceof SMTPMessage)
notify = ((SMTPMessage)message).getDSNNotify();
if (notify == null)
notify = session.getProperty("mail." + name + ".dsn.notify");
// XXX - check for legal syntax?
if (notify != null)
dsn = true;
}
// try the addresses one at a time
for (int i = 0; i < addresses.length; i++) {
sfex = null;
InternetAddress ia = (InternetAddress)addresses[i];
String cmd = "RCPT TO:" + normalizeAddress(ia.getAddress());
if (dsn)
cmd += " NOTIFY=" + notify;
// send the addresses to the SMTP server
sendCommand(cmd);
// check the server's response for address validity
retCode = readServerResponse();
switch (retCode) {
case 250: case 251:
valid.addElement(ia);
if (!reportSuccess)
break;
// user wants exception even when successful, including
// details of the return code
// create and chain the exception
sfex = new SMTPAddressSucceededException(ia, cmd, retCode,
lastServerResponse);
if (mex == null)
mex = sfex;
else
mex.setNextException(sfex);
break;
case 550: case 553: case 503: case 551: case 501:
// given address is invalid
if (!sendPartial)
sendFailed = true;
invalid.addElement(ia);
// create and chain the exception
sfex = new SMTPAddressFailedException(ia, cmd, retCode,
lastServerResponse);
if (mex == null)
mex = sfex;
else
mex.setNextException(sfex);
break;
case 552: case 450: case 451: case 452:
// given address is valid
if (!sendPartial)
sendFailed = true;
validUnsent.addElement(ia);
// create and chain the exception
sfex = new SMTPAddressFailedException(ia, cmd, retCode,
lastServerResponse);
if (mex == null)
mex = sfex;
else
mex.setNextException(sfex);
break;
default:
// handle remaining 4xy & 5xy codes
if (retCode >= 400 && retCode <= 499) {
// assume address is valid, although we don't really know
validUnsent.addElement(ia);
} else if (retCode >= 500 && retCode <= 599) {
// assume address is invalid, although we don't really know
invalid.addElement(ia);
} else {
// completely unexpected response, just give up
if (debug)
out.println("DEBUG SMTP: got response code " + retCode +
", with response: " + lastServerResponse);
String _lsr = lastServerResponse; // else rset will nuke it
int _lrc = lastReturnCode;
if (serverSocket != null) // hasn't already been closed
issueCommand("RSET", 250);
lastServerResponse = _lsr; // restore, for get
lastReturnCode = _lrc;
throw new SMTPAddressFailedException(ia, cmd, retCode,
_lsr);
}
if (!sendPartial)
sendFailed = true;
// create and chain the exception
sfex = new SMTPAddressFailedException(ia, cmd, retCode,
lastServerResponse);
if (mex == null)
mex = sfex;
else
mex.setNextException(sfex);
break;
}
}
// if we're willing to send to a partial list, and we found no
// valid addresses, that's complete failure
if (sendPartial && valid.size() == 0)
sendFailed = true;
// copy the vectors into appropriate arrays
if (sendFailed) {
// copy invalid addrs
invalidAddr = new Address[invalid.size()];
invalid.copyInto(invalidAddr);
// copy all valid addresses to validUnsent, since something failed
validUnsentAddr = new Address[valid.size() + validUnsent.size()];
int i = 0;
for (int j = 0; j < valid.size(); j++)
validUnsentAddr[i++] = (Address)valid.elementAt(j);
for (int j = 0; j < validUnsent.size(); j++)
validUnsentAddr[i++] = (Address)validUnsent.elementAt(j);
} else if (reportSuccess || (sendPartial &&
(invalid.size() > 0 || validUnsent.size() > 0))) {
// we'll go on to send the message, but after sending we'll
// throw an exception with this exception nested
sendPartiallyFailed = true;
exception = mex;
// copy invalid addrs
invalidAddr = new Address[invalid.size()];
invalid.copyInto(invalidAddr);
// copy valid unsent addresses to validUnsent
validUnsentAddr = new Address[validUnsent.size()];
validUnsent.copyInto(validUnsentAddr);
// copy valid addresses to validSent
validSentAddr = new Address[valid.size()];
valid.copyInto(validSentAddr);
} else { // all addresses pass
validSentAddr = addresses;
}
// print out the debug info
if (debug) {
if (validSentAddr != null && validSentAddr.length > 0) {
out.println("DEBUG SMTP: Verified Addresses");
for (int l = 0; l < validSentAddr.length; l++) {
out.println("DEBUG SMTP: " + validSentAddr[l]);
}
}
if (validUnsentAddr != null && validUnsentAddr.length > 0) {
out.println("DEBUG SMTP: Valid Unsent Addresses");
for (int j = 0; j < validUnsentAddr.length; j++) {
out.println("DEBUG SMTP: " + validUnsentAddr[j]);
}
}
if (invalidAddr != null && invalidAddr.length > 0) {
out.println("DEBUG SMTP: Invalid Addresses");
for (int k = 0; k < invalidAddr.length; k++) {
out.println("DEBUG SMTP: " + invalidAddr[k]);
}
}
}
// throw the exception, fire TransportEvent.MESSAGE_NOT_DELIVERED event
if (sendFailed) {
if (debug)
out.println("DEBUG SMTP: Sending failed " +
"because of invalid destination addresses");
notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED,
validSentAddr, validUnsentAddr,
invalidAddr, this.message);
// reset the connection so more sends are allowed
String lsr = lastServerResponse; // save, for get
int lrc = lastReturnCode;
try {
if (serverSocket != null)
issueCommand("RSET", 250);
} catch (MessagingException ex) {
// if can't reset, best to close the connection
try {
close();
} catch (MessagingException ex2) {
// thrown by close()--ignore, will close() later anyway
if (debug)
ex2.printStackTrace(out);
}
} finally {
lastServerResponse = lsr; // restore
lastReturnCode = lrc;
}
throw new SendFailedException("Invalid Addresses", mex,
validSentAddr,
validUnsentAddr, invalidAddr);
}
}
/**
* Send the <code>DATA</code> command to the SMTP host and return
* an OutputStream to which the data is to be written.
*
* @since JavaMail 1.4.1
*/
protected OutputStream data() throws MessagingException {
assert Thread.holdsLock(this);
issueSendCommand("DATA", 354);
dataStream = new SMTPOutputStream(serverOutput);
return dataStream;
}
/**
* Terminate the sent data.
*
* @since JavaMail 1.4.1
*/
protected void finishData() throws IOException, MessagingException {
assert Thread.holdsLock(this);
dataStream.ensureAtBOL();
issueSendCommand(".", 250);
}
/**
* Issue the <code>STARTTLS</code> command and switch the socket to
* TLS mode if it succeeds.
*
* @since JavaMail 1.4.1
*/
protected void startTLS() throws MessagingException {
issueCommand("STARTTLS", 220);
// it worked, now switch the socket into TLS mode
try {
serverSocket = SocketFetcher.startTLS(serverSocket,
session.getProperties(), "mail." + name);
initStreams();
} catch (IOException ioex) {
closeConnection();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -