    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 *      https://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.nio.charset.StandardCharsets;
    026import java.util.ArrayList;
    027
    028import org.apache.commons.net.MalformedServerReplyException;
    029import org.apache.commons.net.ProtocolCommandSupport;
    030import org.apache.commons.net.SocketClient;
    031import org.apache.commons.net.io.CRLFLineReader;
    032import org.apache.commons.net.util.NetConstants;
    033
    034/**
    035 * 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
    036 * of the FTP protocol defined in RFC 821. However, there is no reason why you should have to use the SMTP class. The
    037 * {@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
    038 * 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
    039 * protocol and implement their own clients. A set of methods with names corresponding to the SMTP command names are provided to facilitate this interaction.
    040 * <p>
    041 * 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
    042 * server connection closing when it receives a {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE} response to
    043 * a command. When that occurs, the SMTP class method encountering that reply will throw an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException}.
    044 * {@code SMTPConnectionClosedException} is a subclass of {@code IOException} and therefore need not be caught separately, but if you are going to
    045 * catch it separately, its catch block must appear before the more general {@code IOException} catch block. When you encounter an
    046 * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} , you must disconnect the connection with
    047 * {@link org.apache.commons.net.SocketClient#disconnect disconnect()} to properly clean up the system resources used by SMTP. Before disconnecting, you may
    048 * check the last reply code and text with {@link #getReplyCode getReplyCode}, {@link #getReplyString getReplyString}, and {@link #getReplyStrings
    049 * getReplyStrings}.
    050 * </p>
    051 * <p>
    052 * 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
    053 * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
    054 * 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
    055 * lenient as possible.
    056 * </p>
    057 *
    058 * @see SMTPClient
    059 * @see SMTPConnectionClosedException
    060 * @see org.apache.commons.net.MalformedServerReplyException
    061 */
    062
    063public class SMTP extends SocketClient {
    064
    065    /** The default SMTP port (25). */
    066    public static final int DEFAULT_PORT = 25;
    067
    068    /**
    069     * 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.
    070     */
    071    private static final String DEFAULT_ENCODING = StandardCharsets.ISO_8859_1.name();
    072
    073    /**
    074     * The encoding to use (user-settable).
    075     *
    076     * @since 3.1 (changed from private to protected)
    077     */
    078    protected final String encoding;
    079
    080    /**
    081     * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and te firing of ProtocolCommandEvents.
    082     */
    083    protected ProtocolCommandSupport _commandSupport_;
    084
    085    BufferedReader reader;
    086    BufferedWriter writer;
    087
    088    private int replyCode;
    089    private final ArrayList<String> replyLines;
    090    private boolean newReplyString;
    091    private String replyString;
    092
    093    /**
    094     * The default SMTP constructor. Sets the default port to {@code DEFAULT_PORT} and initializes internal data structures for saving SMTP reply
    095     * information.
    096     */
    097    public SMTP() {
    098        this(DEFAULT_ENCODING);
    099    }
    100
    101    /**
    102     * Overloaded constructor where the user may specify a default encoding.
    103     *
    104     * @param encoding the encoding to use
    105     * @since 2.0
    106     */
    107    public SMTP(final String encoding) {
    108        setDefaultPort(DEFAULT_PORT);
    109        replyLines = new ArrayList<>();
    110        newReplyString = false;
    111        replyString = null;
    112        _commandSupport_ = new ProtocolCommandSupport(this);
    113        this.encoding = encoding;
    114    }
    115
    116    /** Initiates control connections and gets initial reply. */
    117    @Override
    118    protected void _connectAction_() throws IOException {
    119        super._connectAction_();
    120        reader = new CRLFLineReader(new InputStreamReader(_input_, encoding));
    121        writer = new BufferedWriter(new OutputStreamWriter(_output_, encoding));
    122        getReply();
    123    }
    124
    125    /**
    126     * A convenience method to send the SMTP DATA command to the server, receive the reply, and return the reply code.
    127     *
    128     * @return The reply code received from the server.
    129     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    130     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    131     *                                       independently as itself.
    132     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    133     */
    134    public int data() throws IOException {
    135        return sendCommand(SMTPCommand.DATA);
    136    }
    137
    138    /**
    139     * 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
    140     * and code information from the last command is voided so that the memory it used may be reclaimed.
    141     *
    142     * @throws IOException If an error occurs while disconnecting.
    143     */
    144    @Override
    145    public void disconnect() throws IOException {
    146        super.disconnect();
    147        reader = null;
    148        writer = null;
    149        replyString = null;
    150        replyLines.clear();
    151        newReplyString = false;
    152    }
    153
    154    /**
    155     * A convenience method to send the SMTP VRFY command to the server, receive the reply, and return the reply code.
    156     *
    157     * @param name The name to expand.
    158     * @return The reply code received from the server.
    159     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    160     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    161     *                                       independently as itself.
    162     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    163     */
    164    public int expn(final String name) throws IOException {
    165        return sendCommand(SMTPCommand.EXPN, name);
    166    }
    167
    168    /**
    169     * Provide command support to super-class
    170     */
    171    @Override
    172    protected ProtocolCommandSupport getCommandSupport() {
    173        return _commandSupport_;
    174    }
    175
    176    /**
    177     * Gets 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
    178     * calling {@link #getReplyString getReplyString} or {@link #getReplyStrings getReplyStrings}. Only use this method if you are implementing your own SMTP
    179     * client or if you need to fetch a secondary response from the SMTP server.
    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     * Gets 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} is of type void.
    246     *
    247     * @return The integer value of the reply code of the last SMTP reply.
    248     */
    249    public int getReplyCode() {
    250        return replyCode;
    251    }
    252
    253    /**
    254     * Gets the entire text of the last SMTP server response exactly as it was received, including all end of line markers in NETASCII format.
    255     *
    256     * @return The entire text from the last SMTP response as a String.
    257     */
    258    public String getReplyString() {
    259        final StringBuilder buffer;
    260
    261        if (!newReplyString) {
    262            return replyString;
    263        }
    264
    265        buffer = new StringBuilder();
    266
    267        for (final String line : replyLines) {
    268            buffer.append(line);
    269            buffer.append(NETASCII_EOL);
    270        }
    271
    272        newReplyString = false;
    273
    274        replyString = buffer.toString();
    275        return replyString;
    276    }
    277
    278    /**
    279     * Gets 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
    280     * from each line.
    281     *
    282     * @return The lines of text from the last SMTP response as an array.
    283     */
    284    public String[] getReplyStrings() {
    285        return replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY);
    286    }
    287
    288    /**
    289     * A convenience method to send the SMTP HELO command to the server, receive the reply, and return the reply code.
    290     *
    291     * @param hostname The hostname of the sender.
    292     * @return The reply code received from the server.
    293     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    294     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    295     *                                       independently as itself.
    296     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    297     */
    298    public int helo(final String hostname) throws IOException {
    299        return sendCommand(SMTPCommand.HELO, hostname);
    300    }
    301
    302    /**
    303     * A convenience method to send the SMTP HELP command to the server, receive the reply, and return the reply code.
    304     *
    305     * @return The reply code received from the server.
    306     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    307     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    308     *                                       independently as itself.
    309     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    310     */
    311    public int help() throws IOException {
    312        return sendCommand(SMTPCommand.HELP);
    313    }
    314
    315    /**
    316     * A convenience method to send the SMTP HELP command to the server, receive the reply, and return the reply code.
    317     *
    318     * @param command The command name on which to request help.
    319     * @return The reply code received from the server.
    320     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    321     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    322     *                                       independently as itself.
    323     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    324     */
    325    public int help(final String command) throws IOException {
    326        return sendCommand(SMTPCommand.HELP, command);
    327    }
    328
    329    /**
    330     * A convenience method to send the SMTP MAIL command to the server, receive the reply, and return the reply code.
    331     *
    332     * @param reversePath The reverse path.
    333     * @return The reply code received from the server.
    334     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    335     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    336     *                                       independently as itself.
    337     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    338     */
    339    public int mail(final String reversePath) throws IOException {
    340        return sendCommand(SMTPCommand.MAIL, reversePath, false);
    341    }
    342
    343    /**
    344     * A convenience method to send the SMTP NOOP command to the server, receive the reply, and return the reply code.
    345     *
    346     * @return The reply code received from the server.
    347     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    348     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    349     *                                       independently as itself.
    350     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    351     */
    352    public int noop() throws IOException {
    353        return sendCommand(SMTPCommand.NOOP);
    354    }
    355
    356    /**
    357     * A convenience method to send the SMTP QUIT command to the server, receive the reply, and return the reply code.
    358     *
    359     * @return The reply code received from the server.
    360     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    361     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    362     *                                       independently as itself.
    363     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    364     */
    365    public int quit() throws IOException {
    366        return sendCommand(SMTPCommand.QUIT);
    367    }
    368
    369    /**
    370     * A convenience method to send the SMTP RCPT command to the server, receive the reply, and return the reply code.
    371     *
    372     * @param forwardPath The forward path.
    373     * @return The reply code received from the server.
    374     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    375     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    376     *                                       independently as itself.
    377     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    378     */
    379    public int rcpt(final String forwardPath) throws IOException {
    380        return sendCommand(SMTPCommand.RCPT, forwardPath, false);
    381    }
    382
    383    /**
    384     * Removes a ProtocolCommandListener.
    385     *
    386     * Delegates this incorrectly named method - removeProtocolCommandistener (note the missing "L")- to the correct method
    387     * {@link SocketClient#removeProtocolCommandListener}
    388     *
    389     * @param listener The ProtocolCommandListener to remove
    390     */
    391    public void removeProtocolCommandistener(final org.apache.commons.net.ProtocolCommandListener listener) {
    392        removeProtocolCommandListener(listener);
    393    }
    394
    395    /**
    396     * A convenience method to send the SMTP RSET command to the server, receive the reply, and return the reply code.
    397     *
    398     * @return The reply code received from the server.
    399     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    400     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    401     *                                       independently as itself.
    402     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    403     */
    404    public int rset() throws IOException {
    405        return sendCommand(SMTPCommand.RSET);
    406    }
    407
    408    /**
    409     * A convenience method to send the SMTP SAML command to the server, receive the reply, and return the reply code.
    410     *
    411     * @param reversePath The reverse path.
    412     * @return The reply code received from the server.
    413     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    414     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    415     *                                       independently as itself.
    416     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    417     */
    418    public int saml(final String reversePath) throws IOException {
    419        return sendCommand(SMTPCommand.SAML, reversePath);
    420    }
    421
    422    /**
    423     * A convenience method to send the SMTP SEND command to the server, receive the reply, and return the reply code.
    424     *
    425     * @param reversePath The reverse path.
    426     * @return The reply code received from the server.
    427     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    428     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    429     *                                       independently as itself.
    430     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    431     */
    432    public int send(final String reversePath) throws IOException {
    433        return sendCommand(SMTPCommand.SEND, reversePath);
    434    }
    435
    436    /**
    437     * 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
    438     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString} or {@link #getReplyStrings getReplyStrings}.
    439     *
    440     * @param command The SMTPCommand constant corresponding to the SMTP command to send.
    441     * @return The integer value of the SMTP reply code returned by the server in response to the command.
    442     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    443     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    444     *                                       independently as itself.
    445     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    446     */
    447    public int sendCommand(final int command) throws IOException {
    448        return sendCommand(command, null);
    449    }
    450
    451    /**
    452     * Sends an SMTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    453     * actual reply text can be accessed by calling {@link #getReplyString getReplyString} or {@link #getReplyStrings getReplyStrings}.
    454     *
    455     * @param command The SMTPCommand constant corresponding to the SMTP command to send.
    456     * @param args    The arguments to the SMTP command. If this parameter is set to null, then the command is sent with no argument.
    457     * @return The integer value of the SMTP reply code returned by the server in response to the command.
    458     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    459     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    460     *                                       independently as itself.
    461     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    462     */
    463    public int sendCommand(final int command, final String args) throws IOException {
    464        return sendCommand(SMTPCommand.getCommand(command), args);
    465    }
    466
    467    /**
    468     *
    469     * @param command      the command to send (as an int defined in {@link SMTPCommand})
    470     * @param args         the command arguments, may be {@code null}
    471     * @param includeSpace if {@code true}, add a space between the command and its arguments
    472     * @return the reply code
    473     * @throws IOException
    474     */
    475    private int sendCommand(final int command, final String args, final boolean includeSpace) throws IOException {
    476        return sendCommand(SMTPCommand.getCommand(command), args, includeSpace);
    477    }
    478
    479    /**
    480     * 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
    481     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString} or {@link #getReplyStrings getReplyStrings}.
    482     *
    483     * @param command The text representation of the SMTP command to send.
    484     * @return The integer value of the SMTP reply code returned by the server in response to the command.
    485     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    486     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    487     *                                       independently as itself.
    488     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    489     */
    490    public int sendCommand(final String command) throws IOException {
    491        return sendCommand(command, null);
    492    }
    493
    494    /**
    495     * Sends an SMTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    496     * actual reply text can be accessed by calling {@link #getReplyString getReplyString} or {@link #getReplyStrings getReplyStrings}.
    497     *
    498     * @param command The text representation of the SMTP command to send.
    499     * @param args    The arguments to the SMTP command. If this parameter is set to null, then the command is sent with no argument.
    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, final String args) throws IOException {
    507        return sendCommand(command, args, true);
    508    }
    509
    510    /**
    511     * Send a command to the server. May also be used to send text data.
    512     *
    513     * @param command      the command to send (as a plain String)
    514     * @param args         the command arguments, may be {@code null}
    515     * @param includeSpace if {@code true}, add a space between the command and its arguments
    516     * @return the reply code
    517     * @throws IOException
    518     */
    519    private int sendCommand(final String command, final String args, final boolean includeSpace) throws IOException {
    520        final StringBuilder builder = new StringBuilder(command);
    521        if (args != null) {
    522            if (includeSpace) {
    523                builder.append(' ');
    524            }
    525            builder.append(args);
    526        }
    527        builder.append(NETASCII_EOL);
    528        final String message = builder.toString();
    529        writer.write(message);
    530        writer.flush();
    531        fireCommandSent(command, message);
    532        return getReply();
    533    }
    534
    535    /**
    536     * A convenience method to send the SMTP SOML command to the server, receive the reply, and return the reply code.
    537     *
    538     * @param reversePath The reverse path.
    539     * @return The reply code received from the server.
    540     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    541     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    542     *                                       independently as itself.
    543     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    544     */
    545    public int soml(final String reversePath) throws IOException {
    546        return sendCommand(SMTPCommand.SOML, reversePath);
    547    }
    548
    549    /**
    550     * A convenience method to send the SMTP TURN command to the server, receive the reply, and return the reply code.
    551     *
    552     * @return The reply code received from the server.
    553     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    554     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    555     *                                       independently as itself.
    556     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    557     */
    558    public int turn() throws IOException {
    559        return sendCommand(SMTPCommand.TURN);
    560    }
    561
    562    /**
    563     * A convenience method to send the SMTP VRFY command to the server, receive the reply, and return the reply code.
    564     *
    565     * @param user The user address to verify.
    566     * @return The reply code received from the server.
    567     * @throws SMTPConnectionClosedException If the SMTP server prematurely closes the connection as a result of the client being idle or some other reason
    568     *                                       causing the server to send SMTP reply code 421. This exception may be caught either as an IOException or
    569     *                                       independently as itself.
    570     * @throws IOException                   If an I/O error occurs while either sending the command or receiving the server reply.
    571     */
    572    public int vrfy(final String user) throws IOException {
    573        return sendCommand(SMTPCommand.VRFY, user);
    574    }
    575}