private void runCommandLoop() throws IOException {
        if (this.baseSmtpServerRunnable.hasTooManyConnections()) {
            LOGGER.debug("SMTP Too many connections!");

            this.sendResponse("421 Too many connections, try again later");
            return;
        }

        this.sendResponse("220 " + this.server.getHostName() + " ESMTP " + this.server.getSoftwareName());

        while (!this.quitting) {
            try {
                Optional<String> line = readCommandLine();
                if (line.isPresent()) {
                    LOGGER.debug("Client: {}", line);
                    this.server.getCommandHandler().handleCommand(this, line.get());
                } else {
                    LOGGER.debug("no more lines from client");
                    return;
                }
            } catch (final SocketTimeoutException ex) {
                this.sendResponse("421 Timeout waiting for data from client.");
            } catch (final CRLFTerminatedReader.TerminationException te) {
                final String msg = "501 Syntax error at character position "
                        + te.position()
                        + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1.";

                LOGGER.debug(msg);
                this.sendResponse(msg);
            } catch (final CRLFTerminatedReader.MaxLineLengthException mlle) {
                final String msg = "501 " + mlle.getMessage();

                LOGGER.debug(msg);
                this.sendResponse(msg);
            }
        }
    }
Sends the welcome message and starts receiving and processing client
commands. It quits when {@link #quitting} becomes true or when it can be
noticed or at least assumed that the client no longer sends valid commands,
for example on timeout.

@throws IOException if sending to or receiving from the client fails.
src/main/java/de/gessnerfl/fakesmtp/smtp/server/Session.java