SMTP.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.net.smtp;

  18. import java.io.BufferedReader;
  19. import java.io.BufferedWriter;
  20. import java.io.IOException;
  21. import java.io.InputStreamReader;
  22. import java.io.OutputStreamWriter;
  23. import java.nio.charset.StandardCharsets;
  24. import java.util.ArrayList;

  25. import org.apache.commons.net.MalformedServerReplyException;
  26. import org.apache.commons.net.ProtocolCommandSupport;
  27. import org.apache.commons.net.SocketClient;
  28. import org.apache.commons.net.io.CRLFLineReader;
  29. import org.apache.commons.net.util.NetConstants;

  30. /**
  31.  * SMTP provides the basic the functionality necessary to implement your own SMTP client. To derive the full benefits of the SMTP class requires some knowledge
  32.  * of the FTP protocol defined in RFC 821. However, there is no reason why you should have to use the SMTP class. The
  33.  * {@link org.apache.commons.net.smtp.SMTPClient} class, derived from SMTP, implements all the functionality required of an SMTP client. The SMTP class is made
  34.  * public to provide access to various SMTP constants and to make it easier for adventurous programmers (or those with special needs) to interact with the SMTP
  35.  * protocol and implement their own clients. A set of methods with names corresponding to the SMTP command names are provided to facilitate this interaction.
  36.  * <p>
  37.  * You should keep in mind that the SMTP server may choose to prematurely close a connection for various reasons. The SMTP class will detect a premature SMTP
  38.  * server connection closing when it receives a {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } response to
  39.  * a command. When that occurs, the SMTP class method encountering that reply will throw an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} .
  40.  * <code>SMTPConnectionClosedException</code> is a subclass of <code>IOException</code> and therefore need not be caught separately, but if you are going to
  41.  * catch it separately, its catch block must appear before the more general <code>IOException</code> catch block. When you encounter an
  42.  * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} , you must disconnect the connection with
  43.  * {@link org.apache.commons.net.SocketClient#disconnect disconnect() } to properly clean up the system resources used by SMTP. Before disconnecting, you may
  44.  * check the last reply code and text with {@link #getReplyCode getReplyCode }, {@link #getReplyString getReplyString }, and {@link #getReplyStrings
  45.  * getReplyStrings}.
  46.  * </p>
  47.  * <p>
  48.  * Rather than list it separately for each method, we mention here that every method communicating with the server and throwing an IOException can also throw a
  49.  * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
  50.  * reply received from the server deviates enough from the protocol specification that it cannot be interpreted in a useful manner despite attempts to be as
  51.  * lenient as possible.
  52.  * </p>
  53.  *
  54.  * @see SMTPClient
  55.  * @see SMTPConnectionClosedException
  56.  * @see org.apache.commons.net.MalformedServerReplyException
  57.  */

  58. public class SMTP extends SocketClient {
  59.     /** The default SMTP port (25). */
  60.     public static final int DEFAULT_PORT = 25;

  61.     /**
  62.      * We have to ensure that the protocol communication is in ASCII, but we use ISO-8859-1 just in case 8-bit characters cross the wire.
  63.      */
  64.     private static final String DEFAULT_ENCODING = StandardCharsets.ISO_8859_1.name();

  65.     /**
  66.      * The encoding to use (user-settable).
  67.      *
  68.      * @since 3.1 (changed from private to protected)
  69.      */
  70.     protected final String encoding;

  71.     /**
  72.      * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and te firing of ProtocolCommandEvents.
  73.      */
  74.     protected ProtocolCommandSupport _commandSupport_;

  75.     BufferedReader reader;
  76.     BufferedWriter writer;

  77.     private int replyCode;
  78.     private final ArrayList<String> replyLines;
  79.     private boolean newReplyString;
  80.     private String replyString;

  81.     /**
  82.      * The default SMTP constructor. Sets the default port to <code>DEFAULT_PORT</code> and initializes internal data structures for saving SMTP reply
  83.      * information.
  84.      */
  85.     public SMTP() {
  86.         this(DEFAULT_ENCODING);
  87.     }

  88.     /**
  89.      * Overloaded constructor where the user may specify a default encoding.
  90.      *
  91.      * @param encoding the encoding to use
  92.      * @since 2.0
  93.      */
  94.     public SMTP(final String encoding) {
  95.         setDefaultPort(DEFAULT_PORT);
  96.         replyLines = new ArrayList<>();
  97.         newReplyString = false;
  98.         replyString = null;
  99.         _commandSupport_ = new ProtocolCommandSupport(this);
  100.         this.encoding = encoding;
  101.     }

  102.     /** Initiates control connections and gets initial reply. */
  103.     @Override
  104.     protected void _connectAction_() throws IOException {
  105.         super._connectAction_();
  106.         reader = new CRLFLineReader(new InputStreamReader(_input_, encoding));
  107.         writer = new BufferedWriter(new OutputStreamWriter(_output_, encoding));
  108.         getReply();
  109.     }

  110.     /**
  111.      * A convenience method to send the SMTP DATA command to the server, receive the reply, and return the reply code.
  112.      *
  113.      * @return The reply code received from the server.
  114.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  115.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  116.      *                                       independently as itself.
  117.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  118.      */
  119.     public int data() throws IOException {
  120.         return sendCommand(SMTPCommand.DATA);
  121.     }

  122.     /**
  123.      * Closes the connection to the SMTP server and sets to null some internal data so that the memory may be reclaimed by the garbage collector. The reply text
  124.      * and code information from the last command is voided so that the memory it used may be reclaimed.
  125.      *
  126.      * @throws IOException If an error occurs while disconnecting.
  127.      */
  128.     @Override
  129.     public void disconnect() throws IOException {
  130.         super.disconnect();
  131.         reader = null;
  132.         writer = null;
  133.         replyString = null;
  134.         replyLines.clear();
  135.         newReplyString = false;
  136.     }

  137.     /**
  138.      * A convenience method to send the SMTP VRFY command to the server, receive the reply, and return the reply code.
  139.      *
  140.      * @param name The name to expand.
  141.      * @return The reply code received from the server.
  142.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  143.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  144.      *                                       independently as itself.
  145.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  146.      */
  147.     public int expn(final String name) throws IOException {
  148.         return sendCommand(SMTPCommand.EXPN, name);
  149.     }

  150.     /**
  151.      * Provide command support to super-class
  152.      */
  153.     @Override
  154.     protected ProtocolCommandSupport getCommandSupport() {
  155.         return _commandSupport_;
  156.     }

  157.     /**
  158.      * Fetches a reply from the SMTP server and returns the integer reply code. After calling this method, the actual reply text can be accessed from either
  159.      * calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }. Only use this method if you are implementing your own SMTP
  160.      * client or if you need to fetch a secondary response from the SMTP server.
  161.      *
  162.      * @return The integer value of the reply code of the fetched SMTP reply.
  163.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  164.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  165.      *                                       independently as itself.
  166.      * @throws IOException                   If an I/O error occurs while receiving the server reply.
  167.      */
  168.     public int getReply() throws IOException {
  169.         final int length;

  170.         newReplyString = true;
  171.         replyLines.clear();

  172.         String line = reader.readLine();

  173.         if (line == null) {
  174.             throw new SMTPConnectionClosedException("Connection closed without indication.");
  175.         }

  176.         // In case we run into an anomaly we don't want fatal index exceptions
  177.         // to be thrown.
  178.         length = line.length();
  179.         if (length < 3) {
  180.             throw new MalformedServerReplyException("Truncated server reply: " + line);
  181.         }

  182.         try {
  183.             final String code = line.substring(0, 3);
  184.             replyCode = Integer.parseInt(code);
  185.         } catch (final NumberFormatException e) {
  186.             throw new MalformedServerReplyException("Could not parse response code.\nServer Reply: " + line);
  187.         }

  188.         replyLines.add(line);

  189.         // Get extra lines if message continues.
  190.         if (length > 3 && line.charAt(3) == '-') {
  191.             do {
  192.                 line = reader.readLine();

  193.                 if (line == null) {
  194.                     throw new SMTPConnectionClosedException("Connection closed without indication.");
  195.                 }

  196.                 replyLines.add(line);

  197.                 // The length() check handles problems that could arise from readLine()
  198.                 // returning too soon after encountering a naked CR or some other
  199.                 // anomaly.
  200.             } while (!(line.length() >= 4 && line.charAt(3) != '-' && Character.isDigit(line.charAt(0))));
  201.             // This is too strong a condition because a non-conforming server
  202.             // could screw things up like ftp.funet.fi does for FTP
  203.             // line.startsWith(code)));
  204.         }

  205.         fireReplyReceived(replyCode, getReplyString());

  206.         if (replyCode == SMTPReply.SERVICE_NOT_AVAILABLE) {
  207.             throw new SMTPConnectionClosedException("SMTP response 421 received.  Server closed connection.");
  208.         }
  209.         return replyCode;
  210.     }

  211.     /**
  212.      * Returns the integer value of the reply code of the last SMTP reply. You will usually only use this method after you connect to the SMTP server to check
  213.      * that the connection was successful since <code>connect</code> is of type void.
  214.      *
  215.      * @return The integer value of the reply code of the last SMTP reply.
  216.      */
  217.     public int getReplyCode() {
  218.         return replyCode;
  219.     }

  220.     /**
  221.      * Returns the entire text of the last SMTP server response exactly as it was received, including all end of line markers in NETASCII format.
  222.      *
  223.      * @return The entire text from the last SMTP response as a String.
  224.      */
  225.     public String getReplyString() {
  226.         final StringBuilder buffer;

  227.         if (!newReplyString) {
  228.             return replyString;
  229.         }

  230.         buffer = new StringBuilder();

  231.         for (final String line : replyLines) {
  232.             buffer.append(line);
  233.             buffer.append(SocketClient.NETASCII_EOL);
  234.         }

  235.         newReplyString = false;

  236.         replyString = buffer.toString();
  237.         return replyString;
  238.     }

  239.     /**
  240.      * Returns the lines of text from the last SMTP server response as an array of strings, one entry per line. The end of line markers of each are stripped
  241.      * from each line.
  242.      *
  243.      * @return The lines of text from the last SMTP response as an array.
  244.      */
  245.     public String[] getReplyStrings() {
  246.         return replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY);
  247.     }

  248.     /**
  249.      * A convenience method to send the SMTP HELO command to the server, receive the reply, and return the reply code.
  250.      *
  251.      * @param hostname The hostname of the sender.
  252.      * @return The reply code received from the server.
  253.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  254.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  255.      *                                       independently as itself.
  256.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  257.      */
  258.     public int helo(final String hostname) throws IOException {
  259.         return sendCommand(SMTPCommand.HELO, hostname);
  260.     }

  261.     /**
  262.      * A convenience method to send the SMTP HELP command to the server, receive the reply, and return the reply code.
  263.      *
  264.      * @return The reply code received from the server.
  265.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  266.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  267.      *                                       independently as itself.
  268.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  269.      */
  270.     public int help() throws IOException {
  271.         return sendCommand(SMTPCommand.HELP);
  272.     }

  273.     /**
  274.      * A convenience method to send the SMTP HELP command to the server, receive the reply, and return the reply code.
  275.      *
  276.      * @param command The command name on which to request help.
  277.      * @return The reply code received from the server.
  278.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  279.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  280.      *                                       independently as itself.
  281.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  282.      */
  283.     public int help(final String command) throws IOException {
  284.         return sendCommand(SMTPCommand.HELP, command);
  285.     }

  286.     /**
  287.      * A convenience method to send the SMTP MAIL command to the server, receive the reply, and return the reply code.
  288.      *
  289.      * @param reversePath The reverse path.
  290.      * @return The reply code received from the server.
  291.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  292.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  293.      *                                       independently as itself.
  294.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  295.      */
  296.     public int mail(final String reversePath) throws IOException {
  297.         return sendCommand(SMTPCommand.MAIL, reversePath, false);
  298.     }

  299.     /**
  300.      * A convenience method to send the SMTP NOOP command to the server, receive the reply, and return the reply code.
  301.      *
  302.      * @return The reply code received from the server.
  303.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  304.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  305.      *                                       independently as itself.
  306.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  307.      */
  308.     public int noop() throws IOException {
  309.         return sendCommand(SMTPCommand.NOOP);
  310.     }

  311.     /**
  312.      * A convenience method to send the SMTP QUIT command to the server, receive the reply, and return the reply code.
  313.      *
  314.      * @return The reply code received from the server.
  315.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  316.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  317.      *                                       independently as itself.
  318.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  319.      */
  320.     public int quit() throws IOException {
  321.         return sendCommand(SMTPCommand.QUIT);
  322.     }

  323.     /**
  324.      * A convenience method to send the SMTP RCPT command to the server, receive the reply, and return the reply code.
  325.      *
  326.      * @param forwardPath The forward path.
  327.      * @return The reply code received from the server.
  328.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  329.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  330.      *                                       independently as itself.
  331.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  332.      */
  333.     public int rcpt(final String forwardPath) throws IOException {
  334.         return sendCommand(SMTPCommand.RCPT, forwardPath, false);
  335.     }

  336.     /**
  337.      * Removes a ProtocolCommandListener.
  338.      *
  339.      * Delegates this incorrectly named method - removeProtocolCommandistener (note the missing "L")- to the correct method
  340.      * {@link SocketClient#removeProtocolCommandListener}
  341.      *
  342.      * @param listener The ProtocolCommandListener to remove
  343.      */
  344.     public void removeProtocolCommandistener(final org.apache.commons.net.ProtocolCommandListener listener) {
  345.         removeProtocolCommandListener(listener);
  346.     }

  347.     /**
  348.      * A convenience method to send the SMTP RSET command to the server, receive the reply, and return the reply code.
  349.      *
  350.      * @return The reply code received from the server.
  351.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  352.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  353.      *                                       independently as itself.
  354.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  355.      */
  356.     public int rset() throws IOException {
  357.         return sendCommand(SMTPCommand.RSET);
  358.     }

  359.     /**
  360.      * A convenience method to send the SMTP SAML command to the server, receive the reply, and return the reply code.
  361.      *
  362.      * @param reversePath The reverse path.
  363.      * @return The reply code received from the server.
  364.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  365.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  366.      *                                       independently as itself.
  367.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  368.      */
  369.     public int saml(final String reversePath) throws IOException {
  370.         return sendCommand(SMTPCommand.SAML, reversePath);
  371.     }

  372.     /**
  373.      * A convenience method to send the SMTP SEND command to the server, receive the reply, and return the reply code.
  374.      *
  375.      * @param reversePath The reverse path.
  376.      * @return The reply code received from the server.
  377.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  378.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  379.      *                                       independently as itself.
  380.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  381.      */
  382.     public int send(final String reversePath) throws IOException {
  383.         return sendCommand(SMTPCommand.SEND, reversePath);
  384.     }

  385.     /**
  386.      * Sends an SMTP command with no arguments to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed
  387.      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  388.      *
  389.      * @param command The SMTPCommand constant corresponding to the SMTP command to send.
  390.      * @return The integer value of the SMTP reply code returned by the server in response to the command.
  391.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  392.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  393.      *                                       independently as itself.
  394.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  395.      */
  396.     public int sendCommand(final int command) throws IOException {
  397.         return sendCommand(command, null);
  398.     }

  399.     /**
  400.      * Sends an SMTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  401.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  402.      *
  403.      * @param command The SMTPCommand constant corresponding to the SMTP command to send.
  404.      * @param args    The arguments to the SMTP command. If this parameter is set to null, then the command is sent with no argument.
  405.      * @return The integer value of the SMTP reply code returned by the server in response to the command.
  406.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  407.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  408.      *                                       independently as itself.
  409.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  410.      */
  411.     public int sendCommand(final int command, final String args) throws IOException {
  412.         return sendCommand(SMTPCommand.getCommand(command), args);
  413.     }

  414.     /**
  415.      *
  416.      * @param command      the command to send (as an int defined in {@link SMTPCommand})
  417.      * @param args         the command arguments, may be {@code null}
  418.      * @param includeSpace if {@code true}, add a space between the command and its arguments
  419.      * @return the reply code
  420.      * @throws IOException
  421.      */
  422.     private int sendCommand(final int command, final String args, final boolean includeSpace) throws IOException {
  423.         return sendCommand(SMTPCommand.getCommand(command), args, includeSpace);
  424.     }

  425.     /**
  426.      * Sends an SMTP command with no arguments to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed
  427.      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  428.      *
  429.      * @param command The text representation of the SMTP command to send.
  430.      * @return The integer value of the SMTP reply code returned by the server in response to the command.
  431.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  432.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  433.      *                                       independently as itself.
  434.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  435.      */
  436.     public int sendCommand(final String command) throws IOException {
  437.         return sendCommand(command, null);
  438.     }

  439.     /**
  440.      * Sends an SMTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  441.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  442.      *
  443.      * @param command The text representation of the SMTP command to send.
  444.      * @param args    The arguments to the SMTP command. If this parameter is set to null, then the command is sent with no argument.
  445.      * @return The integer value of the SMTP reply code returned by the server in response to the command.
  446.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  447.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  448.      *                                       independently as itself.
  449.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  450.      */
  451.     public int sendCommand(final String command, final String args) throws IOException {
  452.         return sendCommand(command, args, true);
  453.     }

  454.     /**
  455.      * Send a command to the server. May also be used to send text data.
  456.      *
  457.      * @param command      the command to send (as a plain String)
  458.      * @param args         the command arguments, may be {@code null}
  459.      * @param includeSpace if {@code true}, add a space between the command and its arguments
  460.      * @return the reply code
  461.      * @throws IOException
  462.      */
  463.     private int sendCommand(final String command, final String args, final boolean includeSpace) throws IOException {
  464.         final StringBuilder __commandBuffer = new StringBuilder();
  465.         __commandBuffer.append(command);

  466.         if (args != null) {
  467.             if (includeSpace) {
  468.                 __commandBuffer.append(' ');
  469.             }
  470.             __commandBuffer.append(args);
  471.         }

  472.         __commandBuffer.append(SocketClient.NETASCII_EOL);

  473.         final String message = __commandBuffer.toString();
  474.         writer.write(message);
  475.         writer.flush();

  476.         fireCommandSent(command, message);

  477.         return getReply();
  478.     }

  479.     /**
  480.      * A convenience method to send the SMTP SOML command to the server, receive the reply, and return the reply code.
  481.      *
  482.      * @param reversePath The reverse path.
  483.      * @return The reply code received from the server.
  484.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  485.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  486.      *                                       independently as itself.
  487.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  488.      */
  489.     public int soml(final String reversePath) throws IOException {
  490.         return sendCommand(SMTPCommand.SOML, reversePath);
  491.     }

  492.     /**
  493.      * A convenience method to send the SMTP TURN command to the server, receive the reply, and return the reply code.
  494.      *
  495.      * @return The reply code received from the server.
  496.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  497.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  498.      *                                       independently as itself.
  499.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  500.      */
  501.     public int turn() throws IOException {
  502.         return sendCommand(SMTPCommand.TURN);
  503.     }

  504.     /**
  505.      * A convenience method to send the SMTP VRFY command to the server, receive the reply, and return the reply code.
  506.      *
  507.      * @param user The user address to verify.
  508.      * @return The reply code received from the server.
  509.      * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
  510.      *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
  511.      *                                       independently as itself.
  512.      * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
  513.      */
  514.     public int vrfy(final String user) throws IOException {
  515.         return sendCommand(SMTPCommand.VRFY, user);
  516.     }
  517. }