【问题标题】:Is there a way to validate an SMTP configuration using Zend-Mail?有没有办法使用 Zend-Mail 验证 SMTP 配置?
【发布时间】:2016-11-11 13:31:45
【问题描述】:

我一直在用 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 ( "dev@null.com" );
    $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 内置的任何内容。提前感谢任何回答的人!

【问题讨论】:

  • 顺便说一句,您的配置选项与docs.zendframework.com/zend-mail/transport/smtp-authentication/… 中的示例不同。
  • getConfiguration 方法是我类中的自定义方法,它只返回一个与用户配置相关的数组。除此之外,我看不出什么是无效的。它适用于我。也许是因为我在 Magento 中使用 Zend_Mail 而不同?

标签: php magento zend-mail


【解决方案1】:

我在documentation 中没有看到任何表明有一种方法可以只测试 SMTP 身份验证而不实际尝试发送邮件。也许当您调用setOptionssetConnectionConfig 时,它会尝试登录并在失败时抛出异常,但我怀疑不会。

不要在每次发送邮件时都执行验证检查,而是将配置数据和验证结果保存在一个文件中。然后在进行 SMTP 检查之前,读取文件并检查配置设置是否相同。如果是,则只返回保存的结果。

这解决了您的问题列表中的前两项,如果他们的配置无效,他们只会在第一次收到退回电子邮件。

【讨论】:

  • 嘿,你可能误解了我的问题。我正在尝试确定用户的 SMTP 配置是否有效。所以基本上我想用他们的凭据登录 SMTP 服务器,但不发送任何邮件。没有什么可以检查的。
  • 您的脚本尝试发送邮件并检查它是否成功。我建议您保留它,但缓存结果,这样您就不必每次都这样做。
  • 这很好,但我想完全避免这种情况。在 Zend API 中肯定有办法做到这一点,对吧?如果没有,我将不得不通过使用用户提供的配置打开一个套接字来手动检查,然后传递 EHLO 和 AUTH LOGIN 命令。感谢您的回答,我也会尝试整合。
  • “肯定有办法做到这一点”。阅读我的第一段。我扫描了 Zend 文档并没有看到任何暗示。如果您看到我没有看到的内容,那么您应该能够自己回答问题。
  • 抱歉,我的意思是在框架内具有直观的功能。我想我将不得不手动检查。感谢您的帮助和时间:)
【解决方案2】:

我决定手动检查,我将在下面发布最终结果,以便将来对某人有所帮助。感谢@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/

【讨论】:

    猜你喜欢
    • 2012-01-24
    • 2012-09-26
    • 1970-01-01
    • 2015-06-19
    • 2022-11-20
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    相关资源
    最近更新 更多