    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.net.smtp;
    019
    020import java.io.BufferedReader;
    021import java.io.BufferedWriter;
    022import java.io.IOException;
    023import java.io.InputStreamReader;
    024import java.io.OutputStreamWriter;
    025import java.util.ArrayList;
    026
    027import org.apache.commons.net.MalformedServerReplyException;
    028import org.apache.commons.net.ProtocolCommandSupport;
    029import org.apache.commons.net.SocketClient;
    030import org.apache.commons.net.io.CRLFLineReader;
    031import org.apache.commons.net.util.NetConstants;
    032
    033/**
    034 * 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
    035 * of the FTP protocol defined in RFC 821. However, there is no reason why you should have to use the SMTP class. The
    036 * {@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
    037 * 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
    038 * protocol and implement their own clients. A set of methods with names corresponding to the SMTP command names are provided to facilitate this interaction.
    039 * <p>
    040 * 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
    041 * server connection closing when it receives a {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } response to
    042 * a command. When that occurs, the SMTP class method encountering that reply will throw an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} .
    043 * <code>SMTPConectionClosedException</code> is a subclass of <code> IOException </code> and therefore need not be caught separately, but if you are going to
    044 * catch it separately, its catch block must appear before the more general <code> IOException </code> catch block. When you encounter an
    045 * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} , you must disconnect the connection with
    046 * {@link org.apache.commons.net.SocketClient#disconnect disconnect() } to properly clean up the system resources used by SMTP. Before disconnecting, you may
    047 * check the last reply code and text with {@link #getReplyCode getReplyCode }, {@link #getReplyString getReplyString }, and {@link #getReplyStrings
    048 * getReplyStrings}.
    049 * <p>
    050 * 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
    051 * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
    052 * 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
    053 * lenient as possible.
    054 *
    055 * @see SMTPClient
    056 * @see SMTPConnectionClosedException
    057 * @see org.apache.commons.net.MalformedServerReplyException
    058 */
    059
    060public class SMTP extends SocketClient {
    061    /** The default SMTP port (25). */
    062    public static final int DEFAULT_PORT = 25;
    063
    064    // We have to ensure that the protocol communication is in ASCII
    065    // but we use ISO-8859-1 just in case 8-bit characters cross
    066    // the wire.
    067    private static final String DEFAULT_ENCODING = "ISO-8859-1";
    068
    069    /**
    070     * The encoding to use (user-settable).
    071     *
    072     * @since 3.1 (changed from private to protected)
    073     */
    074    protected final String encoding;
    075
    076    /**
    077     * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and te firing of ProtocolCommandEvents.
    078     */
    079    protected ProtocolCommandSupport _commandSupport_;
    080
    081    BufferedReader reader;
    082    BufferedWriter writer;
    083
    084    private int replyCode;
    085    private final ArrayList<String> replyLines;
    086    private boolean newReplyString;
    087    private String replyString;
    088
    089    /**
    090     * The default SMTP constructor. Sets the default port to <code>DEFAULT_PORT</code> and initializes internal data structures for saving SMTP reply
    091     * information.
    092     */
    093    public SMTP() {
    094        this(DEFAULT_ENCODING);
    095    }
    096
    097    /**
    098     * Overloaded constructor where the user may specify a default encoding.
    099     *
    100     * @param encoding the encoing to use
    101     * @since 2.0
    102     */
    103    public SMTP(final String encoding) {
    104        setDefaultPort(DEFAULT_PORT);
    105        replyLines = new ArrayList<>();
    106        newReplyString = false;
    107        replyString = null;
    108        _commandSupport_ = new ProtocolCommandSupport(this);
    109        this.encoding = encoding;
    110    }
    111
    112    /** Initiates control connections and gets initial reply. */
    113    @Override
    114    protected void _connectAction_() throws IOException {
    115        super._connectAction_();
    116        reader = new CRLFLineReader(new InputStreamReader(_input_, encoding));
    117        writer = new BufferedWriter(new OutputStreamWriter(_output_, encoding));
    118        getReply();
    119    }
    120
    121    /**
    122     * A convenience method to send the SMTP DATA command to the server, receive the reply, and return the reply code.
    123     * <p>
    124     *
    125     * @return The reply code received from the server.
    126     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    127     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    128     *                                       independently as itself.
    129     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    130     */
    131    public int data() throws IOException {
    132        return sendCommand(SMTPCommand.DATA);
    133    }
    134
    135    /**
    136     * 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
    137     * and code information from the last command is voided so that the memory it used may be reclaimed.
    138     * <p>
    139     *
    140     * @throws IOException If an error occurs while disconnecting.
    141     */
    142    @Override
    143    public void disconnect() throws IOException {
    144        super.disconnect();
    145        reader = null;
    146        writer = null;
    147        replyString = null;
    148        replyLines.clear();
    149        newReplyString = false;
    150    }
    151
    152    /**
    153     * A convenience method to send the SMTP VRFY command to the server, receive the reply, and return the reply code.
    154     * <p>
    155     *
    156     * @param name The name to expand.
    157     * @return The reply code received from the server.
    158     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    159     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    160     *                                       independently as itself.
    161     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    162     */
    163    public int expn(final String name) throws IOException {
    164        return sendCommand(SMTPCommand.EXPN, name);
    165    }
    166
    167    /**
    168     * Provide command support to super-class
    169     */
    170    @Override
    171    protected ProtocolCommandSupport getCommandSupport() {
    172        return _commandSupport_;
    173    }
    174
    175    /**
    176     * 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
    177     * calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }. Only use this method if you are implementing your own SMTP
    178     * client or if you need to fetch a secondary response from the SMTP server.
    179     * <p>
    180     *
    181     * @return The integer value of the reply code of the fetched SMTP reply.
    182     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    183     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    184     *                                       independently as itself.
    185     * @throws IOException                   If an I/O error occurs while receiving the server reply.
    186     */
    187    public int getReply() throws IOException {
    188        final int length;
    189
    190        newReplyString = true;
    191        replyLines.clear();
    192
    193        String line = reader.readLine();
    194
    195        if (line == null) {
    196            throw new SMTPConnectionClosedException("Connection closed without indication.");
    197        }
    198
    199        // In case we run into an anomaly we don't want fatal index exceptions
    200        // to be thrown.
    201        length = line.length();
    202        if (length < 3) {
    203            throw new MalformedServerReplyException("Truncated server reply: " + line);
    204        }
    205
    206        try {
    207            final String code = line.substring(0, 3);
    208            replyCode = Integer.parseInt(code);
    209        } catch (final NumberFormatException e) {
    210            throw new MalformedServerReplyException("Could not parse response code.\nServer Reply: " + line);
    211        }
    212
    213        replyLines.add(line);
    214
    215        // Get extra lines if message continues.
    216        if (length > 3 && line.charAt(3) == '-') {
    217            do {
    218                line = reader.readLine();
    219
    220                if (line == null) {
    221                    throw new SMTPConnectionClosedException("Connection closed without indication.");
    222                }
    223
    224                replyLines.add(line);
    225
    226                // The length() check handles problems that could arise from readLine()
    227                // returning too soon after encountering a naked CR or some other
    228                // anomaly.
    229            } while (!(line.length() >= 4 && line.charAt(3) != '-' && Character.isDigit(line.charAt(0))));
    230            // This is too strong a condition because a non-conforming server
    231            // could screw things up like ftp.funet.fi does for FTP
    232            // line.startsWith(code)));
    233        }
    234
    235        fireReplyReceived(replyCode, getReplyString());
    236
    237        if (replyCode == SMTPReply.SERVICE_NOT_AVAILABLE) {
    238            throw new SMTPConnectionClosedException("SMTP response 421 received.  Server closed connection.");
    239        }
    240        return replyCode;
    241    }
    242
    243    /**
    244     * 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
    245     * that the connection was successful since <code> connect </code> is of type void.
    246     * <p>
    247     *
    248     * @return The integer value of the reply code of the last SMTP reply.
    249     */
    250    public int getReplyCode() {
    251        return replyCode;
    252    }
    253
    254    /**
    255     * Returns the entire text of the last SMTP server response exactly as it was received, including all end of line markers in NETASCII format.
    256     * <p>
    257     *
    258     * @return The entire text from the last SMTP response as a String.
    259     */
    260    public String getReplyString() {
    261        final StringBuilder buffer;
    262
    263        if (!newReplyString) {
    264            return replyString;
    265        }
    266
    267        buffer = new StringBuilder();
    268
    269        for (final String line : replyLines) {
    270            buffer.append(line);
    271            buffer.append(SocketClient.NETASCII_EOL);
    272        }
    273
    274        newReplyString = false;
    275
    276        replyString = buffer.toString();
    277        return replyString;
    278    }
    279
    280    /**
    281     * 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
    282     * from each line.
    283     * <p>
    284     *
    285     * @return The lines of text from the last SMTP response as an array.
    286     */
    287    public String[] getReplyStrings() {
    288        return replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY);
    289    }
    290
    291    /**
    292     * A convenience method to send the SMTP HELO command to the server, receive the reply, and return the reply code.
    293     * <p>
    294     *
    295     * @param hostname The hostname of the sender.
    296     * @return The reply code received from the server.
    297     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    298     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    299     *                                       independently as itself.
    300     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    301     */
    302    public int helo(final String hostname) throws IOException {
    303        return sendCommand(SMTPCommand.HELO, hostname);
    304    }
    305
    306    /**
    307     * A convenience method to send the SMTP HELP command to the server, receive the reply, and return the reply code.
    308     * <p>
    309     *
    310     * @return The reply code received from the server.
    311     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    312     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    313     *                                       independently as itself.
    314     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    315     */
    316    public int help() throws IOException {
    317        return sendCommand(SMTPCommand.HELP);
    318    }
    319
    320    /**
    321     * A convenience method to send the SMTP HELP command to the server, receive the reply, and return the reply code.
    322     * <p>
    323     *
    324     * @param command The command name on which to request help.
    325     * @return The reply code received from the server.
    326     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    327     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    328     *                                       independently as itself.
    329     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    330     */
    331    public int help(final String command) throws IOException {
    332        return sendCommand(SMTPCommand.HELP, command);
    333    }
    334
    335    /**
    336     * A convenience method to send the SMTP MAIL command to the server, receive the reply, and return the reply code.
    337     * <p>
    338     *
    339     * @param reversePath The reverese path.
    340     * @return The reply code received from the server.
    341     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    342     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    343     *                                       independently as itself.
    344     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    345     */
    346    public int mail(final String reversePath) throws IOException {
    347        return sendCommand(SMTPCommand.MAIL, reversePath, false);
    348    }
    349
    350    /**
    351     * A convenience method to send the SMTP NOOP command to the server, receive the reply, and return the reply code.
    352     * <p>
    353     *
    354     * @return The reply code received from the server.
    355     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    356     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    357     *                                       independently as itself.
    358     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    359     */
    360    public int noop() throws IOException {
    361        return sendCommand(SMTPCommand.NOOP);
    362    }
    363
    364    /**
    365     * A convenience method to send the SMTP QUIT command to the server, receive the reply, and return the reply code.
    366     * <p>
    367     *
    368     * @return The reply code received from the server.
    369     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    370     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    371     *                                       independently as itself.
    372     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    373     */
    374    public int quit() throws IOException {
    375        return sendCommand(SMTPCommand.QUIT);
    376    }
    377
    378    /**
    379     * A convenience method to send the SMTP RCPT command to the server, receive the reply, and return the reply code.
    380     * <p>
    381     *
    382     * @param forwardPath The forward path.
    383     * @return The reply code received from the server.
    384     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    385     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    386     *                                       independently as itself.
    387     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    388     */
    389    public int rcpt(final String forwardPath) throws IOException {
    390        return sendCommand(SMTPCommand.RCPT, forwardPath, false);
    391    }
    392
    393    /**
    394     * Removes a ProtocolCommandListener.
    395     *
    396     * Delegates this incorrectly named method - removeProtocolCommandistener (note the missing "L")- to the correct method
    397     * {@link SocketClient#removeProtocolCommandListener}
    398     *
    399     * @param listener The ProtocolCommandListener to remove
    400     */
    401    public void removeProtocolCommandistener(final org.apache.commons.net.ProtocolCommandListener listener) {
    402        removeProtocolCommandListener(listener);
    403    }
    404
    405    /**
    406     * A convenience method to send the SMTP RSET command to the server, receive the reply, and return the reply code.
    407     * <p>
    408     *
    409     * @return The reply code received from the server.
    410     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    411     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    412     *                                       independently as itself.
    413     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    414     */
    415    public int rset() throws IOException {
    416        return sendCommand(SMTPCommand.RSET);
    417    }
    418
    419    /**
    420     * A convenience method to send the SMTP SAML command to the server, receive the reply, and return the reply code.
    421     * <p>
    422     *
    423     * @param reversePath The reverese path.
    424     * @return The reply code received from the server.
    425     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    426     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    427     *                                       independently as itself.
    428     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    429     */
    430    public int saml(final String reversePath) throws IOException {
    431        return sendCommand(SMTPCommand.SAML, reversePath);
    432    }
    433
    434    /**
    435     * A convenience method to send the SMTP SEND command to the server, receive the reply, and return the reply code.
    436     * <p>
    437     *
    438     * @param reversePath The reverese path.
    439     * @return The reply code received from the server.
    440     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    441     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    442     *                                       independently as itself.
    443     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    444     */
    445    public int send(final String reversePath) throws IOException {
    446        return sendCommand(SMTPCommand.SEND, reversePath);
    447    }
    448
    449    /**
    450     * 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
    451     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    452     * <p>
    453     *
    454     * @param command The SMTPCommand constant corresponding to the SMTP command to send.
    455     * @return The integer value of the SMTP reply code returned by the server in response to the command.
    456     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    457     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    458     *                                       independently as itself.
    459     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    460     */
    461    public int sendCommand(final int command) throws IOException {
    462        return sendCommand(command, null);
    463    }
    464
    465    /**
    466     * Sends an SMTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    467     * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    468     * <p>
    469     *
    470     * @param command The SMTPCommand constant corresponding to the SMTP command to send.
    471     * @param args    The arguments to the SMTP command. If this parameter is set to null, then the command is sent with no argument.
    472     * @return The integer value of the SMTP reply code returned by the server in response to the command.
    473     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    474     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    475     *                                       independently as itself.
    476     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    477     */
    478    public int sendCommand(final int command, final String args) throws IOException {
    479        return sendCommand(SMTPCommand.getCommand(command), args);
    480    }
    481
    482    /**
    483     *
    484     * @param command      the command to send (as an int defined in {@link SMPTCommand})
    485     * @param args         the command arguments, may be {@code null}
    486     * @param includeSpace if {@code true}, add a space between the command and its arguments
    487     * @return the reply code
    488     * @throws IOException
    489     */
    490    private int sendCommand(final int command, final String args, final boolean includeSpace) throws IOException {
    491        return sendCommand(SMTPCommand.getCommand(command), args, includeSpace);
    492    }
    493
    494    /**
    495     * 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
    496     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    497     * <p>
    498     *
    499     * @param command The text representation of the SMTP command to send.
    500     * @return The integer value of the SMTP reply code returned by the server in response to the command.
    501     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    502     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    503     *                                       independently as itself.
    504     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    505     */
    506    public int sendCommand(final String command) throws IOException {
    507        return sendCommand(command, null);
    508    }
    509
    510    /**
    511     * Sends an SMTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    512     * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    513     * <p>
    514     *
    515     * @param command The text representation of the SMTP command to send.
    516     * @param args    The arguments to the SMTP command. If this parameter is set to null, then the command is sent with no argument.
    517     * @return The integer value of the SMTP reply code returned by the server in response to the command.
    518     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    519     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    520     *                                       independently as itself.
    521     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    522     */
    523    public int sendCommand(final String command, final String args) throws IOException {
    524        return sendCommand(command, args, true);
    525    }
    526
    527    /**
    528     * Send a command to the server. May also be used to send text data.
    529     *
    530     * @param command      the command to send (as a plain String)
    531     * @param args         the command arguments, may be {@code null}
    532     * @param includeSpace if {@code true}, add a space between the command and its arguments
    533     * @return the reply code
    534     * @throws IOException
    535     */
    536    private int sendCommand(final String command, final String args, final boolean includeSpace) throws IOException {
    537        final StringBuilder __commandBuffer = new StringBuilder();
    538        __commandBuffer.append(command);
    539
    540        if (args != null) {
    541            if (includeSpace) {
    542                __commandBuffer.append(' ');
    543            }
    544            __commandBuffer.append(args);
    545        }
    546
    547        __commandBuffer.append(SocketClient.NETASCII_EOL);
    548
    549        final String message = __commandBuffer.toString();
    550        writer.write(message);
    551        writer.flush();
    552
    553        fireCommandSent(command, message);
    554
    555        return getReply();
    556    }
    557
    558    /**
    559     * A convenience method to send the SMTP SOML command to the server, receive the reply, and return the reply code.
    560     * <p>
    561     *
    562     * @param reversePath The reverese path.
    563     * @return The reply code received from the server.
    564     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    565     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    566     *                                       independently as itself.
    567     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    568     */
    569    public int soml(final String reversePath) throws IOException {
    570        return sendCommand(SMTPCommand.SOML, reversePath);
    571    }
    572
    573    /**
    574     * A convenience method to send the SMTP TURN command to the server, receive the reply, and return the reply code.
    575     * <p>
    576     *
    577     * @return The reply code received from the server.
    578     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    579     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    580     *                                       independently as itself.
    581     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    582     */
    583    public int turn() throws IOException {
    584        return sendCommand(SMTPCommand.TURN);
    585    }
    586
    587    /**
    588     * A convenience method to send the SMTP VRFY command to the server, receive the reply, and return the reply code.
    589     * <p>
    590     *
    591     * @param user The user address to verify.
    592     * @return The reply code received from the server.
    593     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    594     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    595     *                                       independently as itself.
    596     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    597     */
    598    public int vrfy(final String user) throws IOException {
    599        return sendCommand(SMTPCommand.VRFY, user);
    600    }
    601}