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