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