Search code examples
phpmagentozend-mail

Is there a way to validate an SMTP configuration using Zend-Mail?


I have been working on a class in PHP to send out mail and I decided to use the Zend framework. This class sends out mail using a user's SMTP configuration. As of right now I am checking a user's SMTP configuration by using the supplied user credentials, and sending out a "dummy" email to a "dummy" email address, and catching the ZendException class that may be thrown on error. This is a horrible method, because of many reasons:

  • The SMTP user get's banned eventually for suspected "Spamming" (GMail)
  • Inefficient and time consuming
  • Failed email delivery attempt is in user's mailbox

The following is an example of what I am doing right now to test if a SMTP configuration is valid:

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;
    }
}

So my question is: Is there a better way of doing this? Does Zend_Mail have a built in feature like this? I have looked all over and couldn't find anything build-in into Zend_Mail. Thank you in advance to whoever answers!


Solution

  • I decided to check manually, I will post the end result below so it may help someone in the future. Thanks to @Barmar for helping me search through the documentation and coming to the result that the Zend_Mail framework doesn't support such a feature. The below methods only work for SSL unfortunately since TLS involves encrypting after the EHLO command (and much more). If the configuration is valid, then it returns true, otherwise it returns the reason it is invalid in string form.

    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;
        }
    

    I came up with this by using the following example: http://schoudhury.com/blog/articles/send-email-using-gmail-from-php-with-fsockopen/