All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.ext.mail.impl.SMTPInitialDialogue Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (c) 2011-2015 The original author or authors
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *       The Eclipse Public License is available at
 *       http://www.eclipse.org/legal/epl-v10.html
 *
 *       The Apache License v2.0 is available at
 *       http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */

package io.vertx.ext.mail.impl;

import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.internal.ContextInternal;
import io.vertx.core.internal.logging.Logger;
import io.vertx.core.internal.logging.LoggerFactory;
import io.vertx.ext.mail.MailConfig;
import io.vertx.ext.mail.StartTLSOptions;

/**
 * Handle welcome line, EHLO/HELO, capabilities
 * and STARTTLS if necessary
 *
 * @author Alexander Lehmann
 */
class SMTPInitialDialogue {

  private static final Logger log = LoggerFactory.getLogger(SMTPInitialDialogue.class);

  private final SMTPConnection connection;

  private final MailConfig config;

  private final String hostname;

  private final Promise promise;

  public SMTPInitialDialogue(ContextInternal context, SMTPConnection connection, MailConfig config, String hostname) {
    this.connection = connection;
    this.config = config;
    this.hostname = hostname;
    this.promise = context.promise();
    this.connection.setExceptionHandler(promise::fail);
  }

  public Future start(final String serverGreeting) {
    SMTPResponse response = new SMTPResponse(serverGreeting);
    if (response.isStatusOk()) {
      if (config.isDisableEsmtp()) {
        helo();
      } else {
        ehlo();
      }
    } else {
      promise.fail(response.toException("got error response"));
    }
    return promise.future();
  }

  private void ehlo() {
    connection.write("EHLO " + hostname).onComplete(ar -> {
      if (ar.failed()) {
        promise.fail(ar.cause());
        return;
      }
      SMTPResponse response = ar.result();
      if (response.isStatusOk()) {
        connection.parseCapabilities(response.getValue());
        if (connection.getCapa().isStartTLS()
          && !connection.isSsl()
          && (config.getStarttls() == StartTLSOptions.REQUIRED || config.getStarttls() == StartTLSOptions.OPTIONAL)) {
          // do not start TLS if we are connected with SSL or are already in TLS
          startTLS();
        } else {
          finished();
        }
      } else {
        // if EHLO fails, assume we have to do HELO
        // if the command is not supported, the response is probably
        // a 5xx error code and we should be able to continue, if not
        // the options disableEsmtp has to be set
        helo();
      }
    });
  }

  private void helo() {
    connection.write("HELO " + hostname).onComplete(ar -> {
      if (ar.failed()) {
        promise.fail(ar.cause());
        return;
      }
      SMTPResponse response = ar.result();
      if (response.isStatusOk()) {
        finished();
      } else {
        promise.fail(response.toException("HELO failed."));
      }
    });
  }

  /**
   * run STARTTLS command and redo EHLO
   */
  private void startTLS() {
    connection.write("STARTTLS")
      .flatMap(ignored -> connection.upgradeToSsl())
      .onComplete(ar -> {
        if (ar.failed()) {
          promise.fail(ar.cause());
          return;
        }
        log.trace("tls started");
        // capabilities may have changed, e.g.
        // if a service only announces PLAIN/LOGIN
        // on secure channel (e.g. googlemail)
        ehlo();
      });
  }

  private void finished() {
    if (connection.isSsl() || config.getStarttls() != StartTLSOptions.REQUIRED) {
      promise.complete();
    } else {
      log.warn("STARTTLS required but not supported by server");
      promise.fail("STARTTLS required but not supported by server");
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy