Есть ли способ проверить конфигурацию SMTP с помощью Zend-Mail?

Я работал над классом в PHP для отправки почты и решил использовать структуру Zend. Этот класс отправляет почту, используя пользовательскую конфигурацию SMTP. На данный момент я проверяю конфигурацию SMTP пользователя, используя предоставленные учетные данные пользователя, отправляю «фиктивное» электронное письмо на «фиктивный» адрес электронной почты и перехватываю класс ZendException, который может быть выдан при ошибке. Это ужасный метод по многим причинам:

  • Пользователь SMTP в конечном итоге забанен за подозрение в «рассылке спама» (GMail)
  • Неэффективно и требует много времени
  • Неудачная попытка доставки электронной почты находится в почтовом ящике пользователя

Ниже приведен пример того, что я сейчас делаю, чтобы проверить правильность конфигурации SMTP:

public function validSMTP () {
    // Get the user's SMTP configuration
    $config = $this->getConfiguration ();
    // Create a new Zend transport SMTP object
    $transport = new Zend_Mail_Transport_Smtp ( $config ["hostname"], [
        "auth"      =>  "login",
        "ssl"       =>  $config ["protocol"],
        "port"      =>  $config ["port"],
        "username"  =>  $config ["from"],
        "password"  =>  $config ["password"]
    ]);
    // Create a new message and send it to dummy email
    $mail = new Zend_Mail ("UTF-8");
    $mail->setBodyText ( "null" );
    $mail->setFrom ( $config ["from"] );
    $mail->addTo ( "[email protected]" );
    $mail->setSubject ( "Test" );
    // Attempt to send the email
    try {
        // Send the email out
        $mail->send ( $transport );
        // If all is well, return true
        return true;
    }
    // Catch all Zend exceptions
    catch ( Zend_Exception $exception ) {
        // Invalid configuration
        return false;
    }
}

Итак, мой вопрос: есть ли лучший способ сделать это? Есть ли в Zend_Mail такая встроенная функция? Я просмотрел все и не смог найти ничего встроенного в Zend_Mail. Заранее спасибо тому, кто ответит!


person Raffi    schedule 08.07.2016    source источник
comment
Кстати, параметры вашей конфигурации не похожи на примеры в документах. zendframework.com/zend-mail/transport/smtp-authentication/.   -  person Barmar    schedule 09.07.2016
comment
Метод getConfiguration является настраиваемым в моем классе, он просто возвращает ассоциативный массив с конфигурацией пользователя. Кроме этого, я не вижу, что может быть недействительным. Это работает на моем конце. Возможно, дело в другом, потому что я использую Zend_Mail в Magento?   -  person Raffi    schedule 09.07.2016


Ответы (2)


Я не вижу в документации ничего, что предполагало бы возможность просто протестировать SMTP. аутентификация без фактической попытки отправить почту. Возможно, когда вы вызываете setOptions или setConnectionConfig, он попытается войти в систему и выдаст исключение в случае неудачи, но я подозреваю, что нет.

Вместо того чтобы выполнять проверку каждый раз, когда вы хотите отправить почту, сохраните данные конфигурации и результаты проверки в файле. Затем, прежде чем выполнять проверку SMTP, прочитайте файл и проверьте, совпадают ли параметры конфигурации. Если они есть, просто верните сохраненные результаты.

Это решает первые два пункта в вашем списке проблем, и они получат отказное электронное письмо только в первый раз, если их конфигурация недействительна.

person Barmar    schedule 08.07.2016
comment
Эй, вы, возможно, неправильно поняли мой вопрос. Я пытаюсь определить, действительна ли конфигурация SMTP пользователя. Итак, в основном я хочу войти на SMTP-сервер со своими учетными данными, но не отправлять почту. Нет ничего, что можно было бы проверить. - person Raffi; 09.07.2016
comment
Ваш скрипт пытается отправить почту и проверяет, удалось ли это. Я предлагаю вам сохранить это, но кэшировать результат, чтобы вам не приходилось делать это каждый раз. - person Barmar; 09.07.2016
comment
Это все хорошо, но я хотел бы избежать этого вообще. Наверняка есть способ сделать это в Zend API? Если нет, мне придется прибегнуть к проверке вручную, открыв сокет, используя конфигурацию, предоставленную пользователем, а затем передав команды EHLO и AUTH LOGIN. Я ценю ваш ответ, я постараюсь интегрировать и это. - person Raffi; 09.07.2016
comment
Наверняка есть способ сделать это. Прочитайте мой первый абзац. Я просмотрел документацию Zend и не увидел ничего такого, что бы подсказывало это. Если вы видите что-то, чего не видел я, то вы должны сами ответить на вопрос. - person Barmar; 09.07.2016
comment
Приношу свои извинения, я имел в виду только то, что это будет интуитивно понятная функциональность в рамках фреймворка. Думаю придется вручную проверять. Спасибо за вашу помощь и время :) - person Raffi; 09.07.2016
comment
Это кажется разумным, но я думаю, они просто предполагают, что вы знаете, что делаете, когда настраиваете его, и вы будете обрабатывать ошибки, когда он терпит неудачу. Они не учитывали потребность в универсальной библиотеке, которая хочет проверять, что делает администратор. - person Barmar; 09.07.2016

Я решил проверить вручную, я опубликую конечный результат ниже, так что это может помочь кому-то в будущем. Спасибо @Barmar за помощь в поиске документации и вывод о том, что среда Zend_Mail не поддерживает такую ​​функцию. К сожалению, приведенные ниже методы работают только для SSL, поскольку TLS включает шифрование после команды EHLO (и многое другое). Если конфигурация действительна, она возвращает true, в противном случае она возвращает причину недопустимости в строковой форме.

public function validSMTP () {
        // Initialize client configuration, for this example
        $config = [
            "hostname"     =>     "smtp.gmail.com",
            "port"         =>     465,
            "protocol"     =>     "ssl",
            "username"     =>     "USERNAME",
            "password"     =>     "PASSWORD",
        ];
        // Add the connection url based on protocol
        $config ["url"] = $config ["protocol"] . "://" . $config ["hostname"];
        // Open a new socket connection to the SMTP mail server
        if ( !( $socket = fsockopen ( $config ["url"], $config ["port"], $en, $es, 15 ) ) ) {
            // Could not establish connection to host
            return "Connection failed, check hostname/port?";
        }
        // Make sure that the protocol is correct
        if ( $this->status_match($socket, '220') === false ) {
            // Probably a wrong protocol (SSL/TLS)
            return "Connection failed, check protocol?";
        }
        // Send hello message to server
        fwrite ( $socket, "EHLO " . $config ["hostname"] ."\r\n" );
        if ( $this->status_match ( $socket, "250" ) === false ) {
            // If Hello fails, say config is invalid
            return "Invalid SMTP configuration";
        }
        // Request to login
        fwrite ( $socket, "AUTH LOGIN\r\n" );
        if ( $this->status_match ( $socket, "334" ) === false ) {
            return "Invalid SMTP configuration";
        }
        // Send the username
        fwrite ( $socket, base64_encode ( $config [ "username" ] ) . "\r\n" );
        if ( $this->status_match ( $socket, "334" ) === false ) {
            // If failed, warn that invalid username password was passed
            return "Invalid username/password combination.";
        }
        // Send the password
        fwrite ( $socket, base64_encode ( $config [ "password" ] ) . "\r\n" );
        if ( $this->status_match ( $socket, "235" )  === false ) {
            // If failed, warn that invalid username password was passed
            return "Invalid username/password combination.";
        }
        // Close the socket connections
        fclose ( $socket );
        // Return true, if everything above passed
        return true;
    }

    private function status_match ( $socket, $expected ) {
        // Initialize the response string
        $response = '';
        // Get response until nothing but code is visible
        while ( substr ( $response, 3, 1) != ' ' ) {
            // Receive 250 bytes
            if ( !( $response = fgets ( $socket, 256 ) ) ) {
                // Break if nothing else to read
                break;
            }
        }
        // If the status code is not what was expected
        if ( !( substr ( $response, 0, 3 ) == $expected ) ) {
            // Return false
            return false;
        }
        // Otherwise return true
        return true;
    }

Я придумал это, используя следующий пример: http://schoudhury.com/blog/articles/send-email-using-gmail-from-php-with-fsockopen/

person Raffi    schedule 09.07.2016