@Override
  public void produceData(final IOSession iosession, final ServerState sessionState)
      throws IOException, SMTPProtocolException {
    Args.notNull(iosession, "IO session");
    Args.notNull(sessionState, "Session state");

    SessionOutputBuffer buf = this.iobuffers.getOutbuf();

    synchronized (sessionState) {
      if (this.actionFuture != null) {
        SMTPReply reply = getReply(this.actionFuture);
        this.actionFuture = null;
        this.writer.write(reply, buf);
      }

      if (this.actionFuture == null) {
        while (!this.pendingActions.isEmpty()) {
          Action<ServerState> action = this.pendingActions.remove();
          Future<SMTPReply> future =
              action.execute(sessionState, new OutputTrigger<SMTPReply>(sessionState, iosession));
          if (future.isDone()) {
            SMTPReply reply = getReply(future);
            this.writer.write(reply, buf);
          } else {
            this.actionFuture = future;
            break;
          }
        }
      }

      if (buf.hasData()) {
        buf.flush(iosession.channel());
      }
      if (!buf.hasData()) {
        if (sessionState.getDataType() != null) {
          this.completed = true;
        }
        if (sessionState.isTerminated()) {
          iosession.close();
        } else {
          iosession.clearEvent(SelectionKey.OP_WRITE);
        }
      }
    }
  }