Forums / Install & configuration / Is SSL supported for SMTP?

Is SSL supported for SMTP?

Author Message

Greg McAvoy-Jensen

Tuesday 30 October 2007 11:10:12 pm

Is there a way to specify SSL communication if one's SMTP server requires an encrypted connection? Thanks!

Granite Horizon, Certified Developer of eZ Publish Web Solutions
Provider of the SaaS Solution Granite Horizon In The Cloud | http://granitehorizon.com/cloud
http://granitehorizon.com | +1 916 647 6350 | California USA | @granitegreg
Blog: http://granitehorizon.com/blog

Mauricio Sánchez

Friday 14 November 2008 2:26:02 pm

I made some tweaks on the smtp class to add support for SSL SMTP connection

Here is the new code for lib/ezutils/classes/ezsmtp.php


<?php
/***************************************
** Filename.......: class.smtp.inc
** Project........: SMTP Class
** Version........: 1.0.5
** Last Modified..: 21 December 2001
***************************************/

    class smtp
    {
        const STATUS_NOT_CONNECTED = 1;
        const STATUS_CONNECTED = 2;
        const CRLF = "\r\n";

        public $authenticated;
        public $connection;
        public $recipients;
        public $CcRecipients;
        public $BccRecipients;
        public $headers;
        public $timeout;
        public $errors;
        public $status;
        public $body;
        public $from;
        public $host;
        public $port;
        public $helo;
        public $auth;
        public $user;
        public $pass;

        /***************************************
        ** Constructor function. Arguments:
        ** $params - An assoc array of parameters:
        **
        **   host    - The hostname of the smtp server        Default: localhost
        **   port    - The port the smtp server runs on        Default: 25
        **   helo    - What to send as the HELO command        Default: localhost
        **             (typically the hostname of the
        **             machine this script runs on)
        **   auth    - Whether to use basic authentication    Default: FALSE
        **   user    - Username for authentication            Default: <blank>
        **   pass    - Password for authentication            Default: <blank>
        **   timeout - The timeout in seconds for the call    Default: 5
        **             to fsockopen()
        ***************************************/

        function smtp( $params = array() )
        {
            $this->authenticated = FALSE;
            $this->timeout       = 5;
            $this->status        = smtp::STATUS_NOT_CONNECTED;
            $this->host          = 'localhost';
            $this->port          = 25;
            $this->helo          = 'localhost';
            $this->auth          = FALSE;
            $this->user          = '';
            $this->pass          = '';
            $this->errors        = array();

            foreach ( $params as $key => $value )
            {
                $this->$key = $value;
            }
        }

        /***************************************
        ** Connect function.
        ** It will connect to the server and send
        ** the HELO command.
        ***************************************/

        function connect($params = array())
        {
            $this->connection = fsockopen( $this->host, $this->port, $errno, $errstr, $this->timeout );
            if ( function_exists( 'socket_set_timeout' ) )
            {
                @socket_set_timeout( $this->connection, 5, 0 );
            }

            $greeting = $this->get_data();
            if ( is_resource( $this->connection ) )
            {
                $result = $this->auth ? $this->ehlo() : $this->helo();
                if ( $result )
                {
                    $this->status = smtp::STATUS_CONNECTED;
                }
                return $result;
            }
            else
            {
                $this->errors[] = 'Failed to connect to server: ' . $errstr;
                return FALSE;
            }
        }

        /***************************************
        ** Function which handles sending the mail.
        ** Arguments:
        ** $params    - Optional assoc array of parameters.
        **            Can contain:
        **              recipients - Indexed array of recipients
        **              from       - The from address. (used in MAIL FROM:),
        **                           this will be the return path
        **              headers    - Indexed array of headers, one header per array entry
        **              body       - The body of the email
        **            It can also contain any of the parameters from the connect()
        **            function
        ***************************************/

        function send( $params = array() )
        {
            foreach ( $params as $key => $value )
            {
                $this->set( $key, $value );
            }

            if ( $this->is_connected() )
            {
                // Do we auth or not? Note the distinction between the auth variable and auth() function
                if ( $this->auth AND !$this->authenticated )
                {
                    if ( !$this->auth() )
                        return FALSE;
                }
                $this->mail( $this->from );
                if ( is_array( $this->recipients ) )
                    foreach ( $this->recipients as $value )
                        $this->rcpt( $value );
                else
                    $this->rcpt( $this->recipients );

                if ( is_array( $this->CcRecipients ) )
                    foreach( $this->CcRecipients as $value )
                        $this->rcpt( $value );
                else
                    $this->rcpt( $this->CcRecipients );

                if ( is_array( $this->BccRecipients ) )
                    foreach ( $this->BccRecipients as $value )
                        $this->rcpt( $value );
                else
                    $this->rcpt( $this->BccRecipients );

                if ( !$this->data() )
                    return FALSE;

                // Transparency
                $headers = str_replace( smtp::CRLF.'.', smtp::CRLF.'..', trim( implode( smtp::CRLF, $this->headers ) ) );
                $body    = str_replace( smtp::CRLF.'.', smtp::CRLF.'..', $this->body );
                $body    = $body[0] == '.' ? '.'.$body : $body;


		// Modify by Mauricio Sánchez - Aplyca Tecnología (24-07-08) 
		//Dealing with SMTP line length limitation (Avoid truncated mails)
                $body = wordwrap($body, 76, "\r\n");
                //End Modify                

                $this->send_data( $headers );
                $this->send_data( '' );
                $this->send_data( $body );
                $this->send_data( '.' );

                $result = ( substr( trim( $this->get_data() ), 0, 3) === '250' );
                return $result;
            }
            else
            {
                $this->errors[] = 'Not connected!';
                return FALSE;
            }
        }

        /***************************************
        ** Function to implement HELO cmd
        ***************************************/

        function helo()
        {
            return( $this->send_cmd( 'HELO ' . $this->helo, '250' ) );
        }


        /***************************************
        ** Function to implement EHLO cmd
        ***************************************/

        function ehlo()
        {
            /* return the result of the EHLO command */
            return ( $this->send_cmd( 'EHLO ' . $this->helo, '250' ) );
        }

        /***************************************
        ** Function to implement RSET cmd
        ***************************************/

        function rset()
        {
            /* return the result of the RSET command */
            return ( $this->send_cmd( 'RSET', '250' ) );
        }

        /***************************************
        ** Function to implement QUIT cmd
        ***************************************/

        function quit()
        {
            /* if QUIT OK */
            if ( $this->send_cmd( 'QUIT', '221' ) )
            {
                /* unset the connection flag and return TRUE */
                $this->status = smtp::STATUS_NOT_CONNECTED;
                return TRUE;
            }
            /* in other case return FALSE */
            return FALSE;
        }

        /***************************************
        ** Function to implement AUTH cmd
        ***************************************/

        function auth()
        {
            /* if the connection is made */
			// Modify by Mauricio Sánchez - Aplyca Tecnología (24-07-08) 
			//Add SMTP secure (SSL) support
			if ( $this->send_cmd( 'STARTTLS', '220' ) )
			{
			    if(!stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) 
				{
					return false;
				}
			//End Modify
	            if ( $this->send_cmd('AUTH LOGIN', '334' ) )
	            {
	                /* if sending username ok */
	                if ( $this->send_cmd( base64_encode( $this->user ), '334' ) )
	                {
	                    /* if sending password ok */
	                    if ( $this->send_cmd( base64_encode( $this->pass ), '235' ) )
	                    {
	                        /* set the authenticated  flag and return TRUE */
	                        $this->authenticated = TRUE;
	                         return TRUE;
	                    }
	                }
	            }
			// Modify by Mauricio Sánchez - Aplyca Tecnología (24-07-08)
			//Add SMTP secure (SSL) support	
			}	
			//End Modify
            /* in other case return FALSE */
            return FALSE;
        }

        /***************************************
        ** Function that handles the MAIL FROM: cmd
        ***************************************/

        function mail( $from )
        {
            /* normalize the from field */
            if ( !preg_match( "/<.+>/", $from ) )
                $from = '<' . $from .'>';

            /* return the result of the MAIL FROM command */
            return ( $this->send_cmd('MAIL FROM:' . $from . '', '250' ) );
        }

        /***************************************
        ** Function that handles the RCPT TO: cmd
        ***************************************/

        function rcpt( $to )
        {
            /* normalize the to field */
            if ( !preg_match( "/<.+>/", $to ) )
                $to = '<' . $to .'>';

            /* return the result of the RCPT TO command */
            return ( $this->send_cmd( 'RCPT TO:' . $to . '', '250' ) );
        }


        /***************************************
        ** Function that sends the DATA cmd
        ***************************************/

        function data()
        {
            /* return the result of the RCPT TO command */
            return ( $this->send_cmd('DATA', '354' ) );
        }

        /***************************************
        ** Function to determine if this object
        ** is connected to the server or not.
        ***************************************/

        function is_connected()
        {
            return ( is_resource( $this->connection ) AND ( $this->status === smtp::STATUS_CONNECTED ) );
        }

        /***************************************
        ** Function to send a bit of data
        ***************************************/

        function send_data( $data )
        {
            if ( is_resource( $this->connection ) )
            {
                return fwrite( $this->connection, $data.smtp::CRLF, strlen( $data ) + 2 );
            }
            else
                return FALSE;
        }

        /***************************************
        ** Function to get data.
        ***************************************/

        function get_data()
        {
            $return = '';
            $line   = '';
            $loops  = 0;

            if ( is_resource( $this->connection ) )
            {
                while ( ( strpos( $return, smtp::CRLF ) === FALSE OR substr( $line, 3, 1 ) !== ' ' ) AND $loops < 100 )
                {
                    $line    = fgets( $this->connection, 512 );
                    $return .= $line;
                    $loops++;
                }
                return $return;
            }
            else
                return FALSE;
        }

        /***************************************
        ** Sets a variable
        ***************************************/

        function set( $var, $value )
        {
            $this->$var = $value;
            return TRUE;
        }

        /********************************************************
        ** Function to simply send a command to the smtp socket
        *********************************************************/
        function send_cmd( $msg, $answer )
        {
            /* if the connection is made */
            if ( $error = is_resource( $this->connection ) )
            {
                /* if sending DATA ok */
                if ( $error = $this->send_data( $msg ) )
                {
                    /* Wait for server answer */
                    $error = $this->get_data();

                    /* return TRUE if the server answered the expected tag */
                    if( substr( trim( $error ), 0, 3 ) === $answer )
                    {
                        return TRUE;
                    }
                }
            }
            /* else return FALSE and set an error */
            $this->errors[] = $msg . ' command failed, output: ' . $error;
            return FALSE;
        }

    } // End of class
?>



Heath

Sunday 16 November 2008 4:08:15 pm

Wow, it looks like you spent some time preparing that code for use with eZ Publish!

You could consider submitting a patch / feature request through the official channels specifically through the mailing list to have your fix included in eZ Publish.

<i>http://ez.no/ezpublish/contributing#bugfixing
http://ez.no/ezpublish/contributing
http://ez.no/developer/developer_information</i>

This process has succeeded in getting new features in eZ Publish for others,
http://www.google.com/search?q=site%3Ahttp%3A%2F%2Flists.ez.no%2Fpipermail%2Fsdk-public%2F+Brookins+Consulting

Cheers,
Heath

Brookins Consulting | http://brookinsconsulting.com/
Certified | http://auth.ez.no/certification/verify/380350
Solutions | http://projects.ez.no/users/community/brookins_consulting
eZpedia community documentation project | http://ezpedia.org

Piotrek Karaś

Sunday 07 December 2008 12:14:56 am

Also, if you need that for custom extensions rather than entire eZ Publish installation, consider Mail Component:
http://ezcomponents.org/docs/tutorials/Mail

--
Company: mediaSELF Sp. z o.o., http://www.mediaself.pl
eZ references: http://ez.no/partners/worldwide_partners/mediaself
eZ certified developer: http://ez.no/certification/verify/272585
eZ blog: http://ez.ryba.eu

Stijn van Esveld

Monday 26 October 2009 1:25:53 pm

Sorry to kick this old topic, but I'm trying to use GMail as SMTP server. I've copied Sanchez code to ezsmtp.php but i can't get the email notification system to work.

In site.ini.append.php i've put the following settings:

[MailSettings]
Transport=smtp
TransportServer=smtp.gmail.com
TransportPort=465
TransportUser=********@gmail.com
TransportPassword=*******
AdminEmail=********@gmail.com
EmailSender=********@gmail.com

I'm getting the following error in the logs:
Unable to connect to SMTP server smtp.gmail.com

I'm running ezpublish version 4.1.1. Is there anyone who got gmail to work with ezpublish or can help with the right settings?

Teru H.

Friday 04 December 2009 7:14:06 pm

http://ez.no/jp/developer/forum/install_configuration/sending_mail_via_gmail_or_google_apps_smtp may help. i haven't tried for gmail but tried for my email account on a rental server.

i haven't succeeded yet, and wonder if there are simpler ways. looking at ezcomponents, for example, it looks like ssl is already supported...