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

1.4k Views Asked by At

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!

2

There are 2 best solutions below

0
Raffi On BEST ANSWER

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/

6
Barmar On

I don't see anything in the documentation that suggests that there's a way to just test the SMTP authentication without actually trying to send mail. Maybe when you call setOptions or setConnectionConfig it will attempt the login and throw an exception if it fails, but I suspect not.

Rather than perform the validation check every time you want to send mail, save the configuration data and validation results in a file. Then before making the SMTP check, read the file and check whether the configuration settings are the same. If they are, just return the saved results.

This solves the first two items in your list of problems, and they'll only get a bounce email the first time if their configuration is invalid.