Fields Summary |
---|
private static final String | softwaretype |
private static final String | OK_RESPONSE |
private static final String | ERR_RESPONSE |
private static final int | AUTHENTICATION_READY |
private static final int | AUTHENTICATION_USERSET |
private static final int | TRANSACTION |
private static final org.apache.mailet.Mail | DELETED |
private POP3HandlerConfigurationData | theConfigDataThe per-service configuration data that applies to all handlers |
private org.apache.james.services.MailRepository | userInboxThe mail server's copy of the user's inbox |
private Thread | handlerThreadThe thread executing this handler |
private Socket | socketThe TCP/IP socket over which the POP3 interaction
is occurring |
private org.apache.james.util.CRLFTerminatedReader | inThe reader associated with incoming characters. |
private PrintWriter | outThe writer to which outgoing messages are written. |
private OutputStream | outsThe socket's output stream |
private int | stateThe current transaction state of the handler |
private String | userThe user id associated with the POP3 dialogue |
private ArrayList | userMailboxA dynamic list representing the set of
emails in the user's inbox at any given time
during the POP3 transaction. |
private ArrayList | backupUserMailbox |
private org.apache.james.util.watchdog.Watchdog | theWatchdogThe watchdog being used by this handler to deal with idle timeouts. |
private org.apache.james.util.watchdog.WatchdogTarget | theWatchdogTargetThe watchdog target that idles out this handler. |
Methods Summary |
---|
private void | doDELE(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a DELE command.
This command deletes a particular mail message from the
mailbox.
String responseString = null;
if (state == TRANSACTION) {
int num = 0;
try {
num = Integer.parseInt(argument);
} catch (Exception e) {
responseString = ERR_RESPONSE + " Usage: DELE [mail number]";
writeLoggedFlushedResponse(responseString);
return;
}
try {
Mail mc = (Mail) userMailbox.get(num);
if (mc == DELETED) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") already deleted.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
} else {
userMailbox.set(num, DELETED);
writeLoggedFlushedResponse(OK_RESPONSE + " Message deleted");
}
} catch (IndexOutOfBoundsException iob) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") does not exist.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
} else {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
|
private void | doLIST(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a LIST command.
Returns the number of messages in the mailbox and its
aggregate size, or optionally, the number and size of
a single message.
String responseString = null;
if (state == TRANSACTION) {
if (argument == null) {
long size = 0;
int count = 0;
try {
for (Iterator i = userMailbox.iterator(); i.hasNext(); ) {
Mail mc = (Mail) i.next();
if (mc != DELETED) {
size += mc.getMessageSize();
count++;
}
}
StringBuffer responseBuffer =
new StringBuffer(32)
.append(OK_RESPONSE)
.append(" ")
.append(count)
.append(" ")
.append(size);
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
count = 0;
for (Iterator i = userMailbox.iterator(); i.hasNext(); count++) {
Mail mc = (Mail) i.next();
if (mc != DELETED) {
responseBuffer =
new StringBuffer(16)
.append(count)
.append(" ")
.append(mc.getMessageSize());
out.println(responseBuffer.toString());
}
}
out.println(".");
out.flush();
} catch (MessagingException me) {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
} else {
int num = 0;
try {
num = Integer.parseInt(argument);
Mail mc = (Mail) userMailbox.get(num);
if (mc != DELETED) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(OK_RESPONSE)
.append(" ")
.append(num)
.append(" ")
.append(mc.getMessageSize());
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
} else {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") already deleted.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
} catch (IndexOutOfBoundsException npe) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") does not exist.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
} catch (NumberFormatException nfe) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" ")
.append(argument)
.append(" is not a valid number");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
} catch (MessagingException me) {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
}
} else {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
|
private void | doNOOP(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a NOOP command.
Like all good NOOPs, does nothing much.
String responseString = null;
if (state == TRANSACTION) {
responseString = OK_RESPONSE;
writeLoggedFlushedResponse(responseString);
} else {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
|
private void | doPASS(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a PASS command.
Reads in and validates the password.
String responseString = null;
if (state == AUTHENTICATION_USERSET && argument != null) {
String passArg = argument;
if (theConfigData.getUsersRepository().test(user, passArg)) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(OK_RESPONSE)
.append(" Welcome ")
.append(user);
responseString = responseBuffer.toString();
state = TRANSACTION;
writeLoggedFlushedResponse(responseString);
userInbox = theConfigData.getMailServer().getUserInbox(user);
stat();
} else {
responseString = ERR_RESPONSE + " Authentication failed.";
state = AUTHENTICATION_READY;
writeLoggedFlushedResponse(responseString);
}
} else {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
|
private void | doQUIT(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a QUIT command.
This method handles cleanup of the POP3Handler state.
String responseString = null;
if (state == AUTHENTICATION_READY || state == AUTHENTICATION_USERSET) {
responseString = OK_RESPONSE + " Apache James POP3 Server signing off.";
writeLoggedFlushedResponse(responseString);
return;
}
List toBeRemoved = ListUtils.subtract(backupUserMailbox, userMailbox);
try {
userInbox.remove(toBeRemoved);
// for (Iterator it = toBeRemoved.iterator(); it.hasNext(); ) {
// Mail mc = (Mail) it.next();
// userInbox.remove(mc.getName());
//}
responseString = OK_RESPONSE + " Apache James POP3 Server signing off.";
writeLoggedFlushedResponse(responseString);
} catch (Exception ex) {
responseString = ERR_RESPONSE + " Some deleted messages were not removed";
writeLoggedFlushedResponse(responseString);
getLogger().error("Some deleted messages were not removed: " + ex.getMessage());
}
|
private void | doRETR(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a RETR command.
This command retrieves a particular mail message from the
mailbox.
String responseString = null;
if (state == TRANSACTION) {
int num = 0;
try {
num = Integer.parseInt(argument.trim());
} catch (Exception e) {
responseString = ERR_RESPONSE + " Usage: RETR [mail number]";
writeLoggedFlushedResponse(responseString);
return;
}
try {
Mail mc = (Mail) userMailbox.get(num);
if (mc != DELETED) {
responseString = OK_RESPONSE + " Message follows";
writeLoggedFlushedResponse(responseString);
try {
ExtraDotOutputStream edouts =
new ExtraDotOutputStream(outs);
OutputStream nouts = new BytesWrittenResetOutputStream(edouts,
theWatchdog,
theConfigData.getResetLength());
mc.getMessage().writeTo(nouts);
nouts.flush();
edouts.checkCRLFTerminator();
edouts.flush();
} finally {
out.println(".");
out.flush();
}
} else {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") already deleted.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
} catch (IOException ioe) {
responseString = ERR_RESPONSE + " Error while retrieving message.";
writeLoggedFlushedResponse(responseString);
} catch (MessagingException me) {
responseString = ERR_RESPONSE + " Error while retrieving message.";
writeLoggedFlushedResponse(responseString);
} catch (IndexOutOfBoundsException iob) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") does not exist.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
} else {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
|
private void | doRSET(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a RSET command.
Calls stat() to reset the mailbox.
String responseString = null;
if (state == TRANSACTION) {
stat();
responseString = OK_RESPONSE;
} else {
responseString = ERR_RESPONSE;
}
writeLoggedFlushedResponse(responseString);
|
private void | doSTAT(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a STAT command.
Returns the number of messages in the mailbox and its
aggregate size.
String responseString = null;
if (state == TRANSACTION) {
long size = 0;
int count = 0;
try {
for (Iterator i = userMailbox.iterator(); i.hasNext(); ) {
Mail mc = (Mail) i.next();
if (mc != DELETED) {
size += mc.getMessageSize();
count++;
}
}
StringBuffer responseBuffer =
new StringBuffer(32)
.append(OK_RESPONSE)
.append(" ")
.append(count)
.append(" ")
.append(size);
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
} catch (MessagingException me) {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
} else {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
|
private void | doTOP(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a TOP command.
This command retrieves the top N lines of a specified
message in the mailbox.
The expected command format is
TOP [mail message number] [number of lines to return]
String responseString = null;
if (state == TRANSACTION) {
int num = 0;
int lines = 0;
try {
num = Integer.parseInt(argument);
lines = Integer.parseInt(argument1);
} catch (NumberFormatException nfe) {
responseString = ERR_RESPONSE + " Usage: TOP [mail number] [Line number]";
writeLoggedFlushedResponse(responseString);
return;
}
try {
Mail mc = (Mail) userMailbox.get(num);
if (mc != DELETED) {
responseString = OK_RESPONSE + " Message follows";
writeLoggedFlushedResponse(responseString);
try {
for (Enumeration e = mc.getMessage().getAllHeaderLines(); e.hasMoreElements(); ) {
out.println(e.nextElement());
}
out.println();
ExtraDotOutputStream edouts =
new ExtraDotOutputStream(outs);
OutputStream nouts = new BytesWrittenResetOutputStream(edouts,
theWatchdog,
theConfigData.getResetLength());
writeMessageContentTo(mc.getMessage(),nouts,lines);
nouts.flush();
edouts.checkCRLFTerminator();
edouts.flush();
} finally {
out.println(".");
out.flush();
}
} else {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") already deleted.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
} catch (IOException ioe) {
responseString = ERR_RESPONSE + " Error while retrieving message.";
writeLoggedFlushedResponse(responseString);
} catch (MessagingException me) {
responseString = ERR_RESPONSE + " Error while retrieving message.";
writeLoggedFlushedResponse(responseString);
} catch (IndexOutOfBoundsException iob) {
StringBuffer exceptionBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") does not exist.");
responseString = exceptionBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
} else {
responseString = ERR_RESPONSE;
writeLoggedFlushedResponse(responseString);
}
|
private void | doUIDL(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a UIDL command.
Returns a listing of message ids to the client.
String responseString = null;
if (state == TRANSACTION) {
if (argument == null) {
responseString = OK_RESPONSE + " unique-id listing follows";
writeLoggedFlushedResponse(responseString);
int count = 0;
for (Iterator i = userMailbox.iterator(); i.hasNext(); count++) {
Mail mc = (Mail) i.next();
if (mc != DELETED) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(count)
.append(" ")
.append(mc.getName());
out.println(responseBuffer.toString());
}
}
out.println(".");
out.flush();
} else {
int num = 0;
try {
num = Integer.parseInt(argument);
Mail mc = (Mail) userMailbox.get(num);
if (mc != DELETED) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(OK_RESPONSE)
.append(" ")
.append(num)
.append(" ")
.append(mc.getName());
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
} else {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") already deleted.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
} catch (IndexOutOfBoundsException npe) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" Message (")
.append(num)
.append(") does not exist.");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
} catch (NumberFormatException nfe) {
StringBuffer responseBuffer =
new StringBuffer(64)
.append(ERR_RESPONSE)
.append(" ")
.append(argument)
.append(" is not a valid number");
responseString = responseBuffer.toString();
writeLoggedFlushedResponse(responseString);
}
}
} else {
writeLoggedFlushedResponse(ERR_RESPONSE);
}
|
private void | doUSER(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of a USER command.
Reads in the user id.
String responseString = null;
if (state == AUTHENTICATION_READY && argument != null) {
user = argument;
state = AUTHENTICATION_USERSET;
responseString = OK_RESPONSE;
} else {
responseString = ERR_RESPONSE;
}
writeLoggedFlushedResponse(responseString);
|
private void | doUnknownCmd(java.lang.String command, java.lang.String argument, java.lang.String argument1)Handler method called upon receipt of an unrecognized command.
Returns an error response and logs the command.
writeLoggedFlushedResponse(ERR_RESPONSE);
|
org.apache.james.util.watchdog.WatchdogTarget | getWatchdogTarget()Gets the Watchdog Target that should be used by Watchdogs managing
this connection.
return theWatchdogTarget;
|
public void | handleConnection(java.net.Socket connection)
String remoteHost = "";
String remoteIP = "";
try {
this.socket = connection;
synchronized (this) {
handlerThread = Thread.currentThread();
}
// in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ASCII"), 512);
in = new CRLFTerminatedReader(new BufferedInputStream(socket.getInputStream(), 512), "ASCII");
remoteIP = socket.getInetAddress().getHostAddress ();
remoteHost = socket.getInetAddress().getHostName ();
} catch (Exception e) {
if (getLogger().isErrorEnabled()) {
StringBuffer exceptionBuffer =
new StringBuffer(256)
.append("Cannot open connection from ")
.append(remoteHost)
.append(" (")
.append(remoteIP)
.append("): ")
.append(e.getMessage());
getLogger().error( exceptionBuffer.toString(), e );
}
}
if (getLogger().isInfoEnabled()) {
StringBuffer logBuffer =
new StringBuffer(128)
.append("Connection from ")
.append(remoteHost)
.append(" (")
.append(remoteIP)
.append(") ");
getLogger().info(logBuffer.toString());
}
try {
outs = new BufferedOutputStream(socket.getOutputStream(), 1024);
out = new InternetPrintWriter(outs, true);
state = AUTHENTICATION_READY;
user = "unknown";
StringBuffer responseBuffer =
new StringBuffer(256)
.append(OK_RESPONSE)
.append(" ")
.append(theConfigData.getHelloName())
.append(" POP3 server (")
.append(POP3Handler.softwaretype)
.append(") ready ");
out.println(responseBuffer.toString());
theWatchdog.start();
while (parseCommand(readCommandLine())) {
theWatchdog.reset();
}
theWatchdog.stop();
if (getLogger().isInfoEnabled()) {
StringBuffer logBuffer =
new StringBuffer(128)
.append("Connection for ")
.append(user)
.append(" from ")
.append(remoteHost)
.append(" (")
.append(remoteIP)
.append(") closed.");
getLogger().info(logBuffer.toString());
}
} catch (Exception e) {
out.println(ERR_RESPONSE + " Error closing connection.");
out.flush();
StringBuffer exceptionBuffer =
new StringBuffer(128)
.append("Exception during connection from ")
.append(remoteHost)
.append(" (")
.append(remoteIP)
.append(") : ")
.append(e.getMessage());
getLogger().error(exceptionBuffer.toString(), e );
} finally {
resetHandler();
}
|
void | idleClose()Idle out this connection
if (getLogger() != null) {
getLogger().error("POP3 Connection has idled out.");
}
try {
if (socket != null) {
socket.close();
}
} catch (Exception e) {
// ignored
} finally {
socket = null;
}
synchronized (this) {
// Interrupt the thread to recover from internal hangs
if (handlerThread != null) {
handlerThread.interrupt();
handlerThread = null;
}
}
|
private final void | logResponseString(java.lang.String responseString)This method logs at a "DEBUG" level the response string that
was sent to the POP3 client. The method is provided largely
as syntactic sugar to neaten up the code base. It is declared
private and final to encourage compiler inlining.
if (getLogger().isDebugEnabled()) {
getLogger().debug("Sent: " + responseString);
}
|
private boolean | parseCommand(java.lang.String rawCommand)This method parses POP3 commands read off the wire in handleConnection.
Actual processing of the command (possibly including additional back and
forth communication with the client) is delegated to one of a number of
command specific handler methods. The primary purpose of this method is
to parse the raw command string to determine exactly which handler should
be called. It returns true if expecting additional commands, false otherwise.
if (rawCommand == null) {
return false;
}
boolean returnValue = true;
String command = rawCommand;
StringTokenizer commandLine = new StringTokenizer(command, " ");
int arguments = commandLine.countTokens();
if (arguments == 0) {
return true;
} else if(arguments > 0) {
command = commandLine.nextToken().toUpperCase(Locale.US);
}
if (getLogger().isDebugEnabled()) {
// Don't display password in logger
if (!command.equals("PASS")) {
getLogger().debug("Command received: " + rawCommand);
} else {
getLogger().debug("Command received: PASS <password omitted>");
}
}
String argument = null;
if(arguments > 1) {
argument = commandLine.nextToken();
}
String argument1 = null;
if(arguments > 2) {
argument1 = commandLine.nextToken();
}
if (command.equals("USER")) {
doUSER(command,argument,argument1);
} else if (command.equals("PASS")) {
doPASS(command,argument,argument1);
} else if (command.equals("STAT")) {
doSTAT(command,argument,argument1);
} else if (command.equals("LIST")) {
doLIST(command,argument,argument1);
} else if (command.equals("UIDL")) {
doUIDL(command,argument,argument1);
} else if (command.equals("RSET")) {
doRSET(command,argument,argument1);
} else if (command.equals("DELE")) {
doDELE(command,argument,argument1);
} else if (command.equals("NOOP")) {
doNOOP(command,argument,argument1);
} else if (command.equals("RETR")) {
doRETR(command,argument,argument1);
} else if (command.equals("TOP")) {
doTOP(command,argument,argument1);
} else if (command.equals("QUIT")) {
returnValue = false;
doQUIT(command,argument,argument1);
} else {
doUnknownCmd(command,argument,argument1);
}
return returnValue;
|
final java.lang.String | readCommandLine()Reads a line of characters off the command line.
for (;;) try {
String commandLine = in.readLine();
if (commandLine != null) {
commandLine = commandLine.trim();
}
return commandLine;
} catch (CRLFTerminatedReader.TerminationException te) {
writeLoggedFlushedResponse("-ERR Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired. See RFC 1939 #3.");
}
|
private void | resetHandler()Resets the handler data to a basic state.
if (theWatchdog != null) {
ContainerUtil.dispose(theWatchdog);
theWatchdog = null;
}
// Close and clear streams, sockets
try {
if (socket != null) {
socket.close();
socket = null;
}
} catch (IOException ioe) {
// Ignoring exception on close
} finally {
socket = null;
}
try {
if (in != null) {
in.close();
}
} catch (Exception e) {
// Ignored
} finally {
in = null;
}
try {
if (out != null) {
out.close();
}
} catch (Exception e) {
// Ignored
} finally {
out = null;
}
try {
if (outs != null) {
outs.close();
}
} catch (Exception e) {
// Ignored
} finally {
outs = null;
}
synchronized (this) {
handlerThread = null;
}
// Clear user data
user = null;
userInbox = null;
if (userMailbox != null) {
userMailbox.clear();
userMailbox = null;
}
if (backupUserMailbox != null) {
backupUserMailbox.clear();
backupUserMailbox = null;
}
// Clear config data
theConfigData = null;
|
void | setConfigurationData(POP3HandlerConfigurationData theData)Set the configuration data for the handler.
theConfigData = theData;
|
void | setWatchdog(org.apache.james.util.watchdog.Watchdog theWatchdog)Set the Watchdog for use by this handler.
this.theWatchdog = theWatchdog;
|
private void | stat()Implements a "stat". If the handler is currently in
a transaction state, this amounts to a rollback of the
mailbox contents to the beginning of the transaction.
This method is also called when first entering the
transaction state to initialize the handler copies of the
user inbox.
userMailbox = new ArrayList();
userMailbox.add(DELETED);
try {
for (Iterator it = userInbox.list(); it.hasNext(); ) {
String key = (String) it.next();
Mail mc = userInbox.retrieve(key);
// Retrieve can return null if the mail is no longer in the store.
// In this case we simply continue to the next key
if (mc == null) {
continue;
}
userMailbox.add(mc);
}
} catch(MessagingException e) {
// In the event of an exception being thrown there may or may not be anything in userMailbox
getLogger().error("Unable to STAT mail box ", e);
}
finally {
backupUserMailbox = (ArrayList) userMailbox.clone();
}
|
final void | writeLoggedFlushedResponse(java.lang.String responseString)Write and flush a response string. The response is also logged.
Should be used for the last line of a multi-line response or
for a single line response.
out.println(responseString);
out.flush();
logResponseString(responseString);
|
final void | writeLoggedResponse(java.lang.String responseString)Write a response string. The response is also logged.
Used for multi-line responses.
out.println(responseString);
logResponseString(responseString);
|
public void | writeMessageContentTo(javax.mail.internet.MimeMessage message, java.io.OutputStream out, int lines)Writes the content of the message, up to a total number of lines, out to
an OutputStream.
String line;
BufferedReader br;
if (message != null) {
br = new BufferedReader(new InputStreamReader(message.getRawInputStream()));
try {
while (lines-- > 0) {
if ((line = br.readLine()) == null) {
break;
}
line += "\r\n";
out.write(line.getBytes());
}
} finally {
br.close();
}
} else {
throw new MessagingException("No message set for this MailImpl.");
}
|