EllisLab text mark
Advanced Search
     
Support for SMTP over TLS (STARTTLS)
Posted: 24 June 2010 01:43 PM
Joined: 2010-06-24
1 posts

My SMTP provider (Exchange system) doesn’t accept SSL connections and requires the use of SMTP over TLS instead (STARTTLS, RFC 3207). Here is a small patch to the Email class which adds support for it. It is written against 1.7.2. If this is useful to others, you’re most welcome to incorporate it in a future release.

Usage:
Specify server settings as a regular SMTP server (tcp://servername, typically port 25 or 587).
Enable new setting in config ($config[‘starttls’] = TRUE;)

Depends on TLS being available (i.e., listed in the ‘Registered Stream Socket Transports’ section of phpinfo()).


Patch

--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -51,+51,@@ class CI_Email {
     
var $send_multipart    TRUE;        // TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override.  Set to FALSE for Yahoo.
     
var    $bcc_batch_mode    FALSE;    // TRUE/FALSE  Turns on/off Bcc batch feature
     
var    $bcc_batch_size    200;      // If bcc_batch_mode = TRUE, sets max number of Bccs in each batch
+    var    $starttls          FALSE;    // Issue STARTTLS after connection to switch to Secure SMTP over TLS (RFC 3207)
     
var $_safe_mode        FALSE;
     var    
$_subject        "";
     var    
$_body            "";
@@ -
1581,+1582,20 @@ class CI_Email {
             
return FALSE;
         
}
 
-        $this->_smtp_connect();
+        if (!
$this->_smtp_connect()) {
+            return FALSE;
+        
}
+
+        if (
$this->starttls{
+            if (! $this->_send_command('starttls')) {
+                $this->_set_error_message('email_starttls_failed');
+                return 
FALSE;
+            
}
+            stream_socket_enable_crypto($this->_smtp_connecttrueSTREAM_CRYPTO_METHOD_TLS_CLIENT);
+            
// Re-issue hello to get updated service list (RFC 3207 section 4.2)
+            $this->_send_command('hello');
+        
}
+
         
$this->_smtp_authenticate();
 
         
$this->_send_command('from'$this->clean_email($this->_headers['From']));
@@ -
1708,+1722,12 @@ class CI_Email {
 
                         $resp 
221;
             break;
+            case 
'starttls'    :
+
+                        
$this->_send_data('STARTTLS');
+
+                        
$resp 220;
+            break;
         
}
 
         $reply 
$this->_get_smtp_data(); 

Example:

<?php
    
function send_email($addr$subject$data{

        $this
->load->library('email');

        
$config['protocol''smtp';
        
$config['smtp_host''tcp://servername'# Not tls:// 
        
$config['smtp_port'25;
        
$config['starttls'TRUE;
        
$config['smtp_user'= <username>;
        
$config['smtp_pass'= <password>;
        
$config['smtp_timeout'5;
        
$config['newline'"\r\n";
        
$config['charset''utf-8';
        
$config['mailtype''html';

        
$this->email->initialize($config);

        
$this->email->from('<email addr>''User name');
        
$this->email->to($addr); 

        
$this->email->subject($subject);
        
$this->email->message($data);

        
$rc $this->email->send();
        echo 
$this->email->print_debugger();
    
}
?> 
 
Posted: 26 July 2010 07:39 PM   [ # 1 ]   [ Rating: 0 ]
Joined: 2007-04-04
61 posts

This was the cure for my google mail problems.

Thanks for this I have added your changes to a library to override the built in Class.

MY_Email in libraries

<?php if (!defined('BASEPATH')) exit('No direct script access allowed.');
class 
MY_Email extends CI_Email {

    
var    $starttls FALSE;    // Issue STARTTLS after connection to switch to Secure SMTP over TLS (RFC 3207)
    
    
function MY_Email()
    
{
        parent
::CI_Email();
        
        
    
}

function _send_with_smtp()
    
{
        
if ($this->smtp_host == '')
        
{
            $this
->_set_error_message('email_no_hostname');
            return 
FALSE;
        
}

        
if (!$this->_smtp_connect()) {
            
return FALSE;
        
}

        
if ($this->starttls{
           
if (! $this->_send_command('starttls')) {
                $this
->_set_error_message('email_starttls_failed');
                return 
FALSE;
            
}
            stream_socket_enable_crypto
($this->_smtp_connecttrueSTREAM_CRYPTO_METHOD_TLS_CLIENT);
            
// Re-issue hello to get updated service list (RFC 3207 section 4.2)
            
$this->_send_command('hello');
        
}

        $this
->_smtp_authenticate();

        
$this->_send_command('from'$this->clean_email($this->_headers['From']));

        foreach(
$this->_recipients as $val)
        
{
            $this
->_send_command('to'$val);
        
}

        
if (count($this->_cc_array) > 0)
        
{
            
foreach($this->_cc_array as $val)
            
{
                
if ($val != "")
                
{
                    $this
->_send_command('to'$val);
                
}
            }
        }

        
if (count($this->_bcc_array) > 0)
        
{
            
foreach($this->_bcc_array as $val)
            
{
                
if ($val != "")
                
{
                    $this
->_send_command('to'$val);
                
}
            }
        }

        $this
->_send_command('data');

        
// perform dot transformation on any lines that begin with a dot
        
$this->_send_data($this->_header_str preg_replace('/^\./m''..$1'$this->_finalbody));

        
$this->_send_data('.');

        
$reply $this->_get_smtp_data();

        
$this->_set_error_message($reply);

        if (
strncmp($reply'250'3) != 0)
        
{
            $this
->_set_error_message('email_smtp_error'$reply);
            return 
FALSE;
        
}

        $this
->_send_command('quit');
        return 
TRUE;
    
}
  
  
      
function _send_command($cmd$data '')
    
{
        
switch ($cmd)
        
{
            
case 'hello' :

                    if (
$this->_smtp_auth OR $this->_get_encoding() == '8bit')
                        
$this->_send_data('EHLO '.$this->_get_hostname());
                    else
                        
$this->_send_data('HELO '.$this->_get_hostname());

                        
$resp 250;
            break;
            case 
'from' :

                        
$this->_send_data('MAIL FROM:<'.$data.'>');

                        
$resp 250;
            break;
            case 
'to'    :

                        
$this->_send_data('RCPT TO:<'.$data.'>');

                        
$resp 250;
            break;
            case 
'data'    :

                        
$this->_send_data('DATA');

                        
$resp 354;
            break;
            case 
'quit'    :

                        
$this->_send_data('QUIT');

                        
$resp 221;
            break;
            case 
'starttls' :

                        
$this->_send_data('STARTTLS');

                        
$resp 220;
            break;
        
}

        $reply 
$this->_get_smtp_data();

        
$this->_debug_msg[] "<pre>".$cmd.": ".$reply."</pre>";

        if (
substr($reply03) != $resp)
        
{
            $this
->_set_error_message('email_smtp_error'$reply);
            return 
FALSE;
        
}

        
if ($cmd == 'quit')
        
{
            fclose
($this->_smtp_connect);
        
}

        
return TRUE;
    
}
    
 Signature 

easy2web

 
Posted: 27 July 2010 07:51 PM   [ # 2 ]   [ Rating: 0 ]
Joined: 2007-04-04
61 posts

For those who come looking I was actually able to fix the google issue simple by adding

'smtp_timeout' => 30
 Signature 

easy2web

 
Posted: 10 October 2011 02:50 PM   [ # 3 ]   [ Rating: 0 ]
Joined: 2011-05-24
4 posts
nicko2n - 24 June 2010 01:43 PM

My SMTP provider (Exchange system) doesn’t accept SSL connections and requires the use of SMTP over TLS instead (STARTTLS, RFC 3207). Here is a small patch to the Email class which adds support for it. It is written against 1.7.2. If this is useful to others, you’re most welcome to incorporate it in a future release.

Usage:
Specify server settings as a regular SMTP server (tcp://servername, typically port 25 or 587).
Enable new setting in config ($config[‘starttls’] = TRUE;)

Thanks for the Exchange Patch Nick! Very useful indeed. Everything worked well with our Exchange server. I noticed you mentioned that this patch needed the tcp:// on the server host name. This was not true for me. It worked without it; just a regular host name. stream_socket_enable_crypto() just encrypts the current connection.

Thanks for the post, Jeff

 

 
Posted: 23 February 2012 04:19 PM   [ # 4 ]   [ Rating: 0 ]
Joined: 2012-02-23
2 posts

As of 2.1.0, you can accomplish this without extending the Email class…

Solution:
For TLS: $config[‘smtp_crypto’] = ‘tls’;
For SSL: $config[‘smtp_crypto’] = ‘ssl’;

Tested it today and it works great!

 
Posted: 13 February 2013 10:50 AM   [ # 5 ]   [ Rating: 0 ]
Avatar
Joined: 2008-06-11
173 posts
Miles - 23 February 2012 04:19 PM

As of 2.1.0, you can accomplish this without extending the Email class…

Solution:
For TLS: $config[‘smtp_crypto’] = ‘tls’;
For SSL: $config[‘smtp_crypto’] = ‘ssl’;

Tested it today and it works great!

I’m running into this issue now. Has this config variable been confirmed? I’m still having trouble over all with getting Freeform (and by extension email sent through the Communicate tab in the CP) and I’m just trying to eliminate things like this so their Exchange Server admin can stop blaming EE and start looking into this from his end. I did have to hack the CI email library to overwrite the port (587 instead of 25) and I had to change the newline and crlf variables to /r/n instead of just /n. Anything else I might have missed? Any other changed to the CI email library that need to be made? Other hidden config variables that need to be set?

 
Posted: 13 February 2013 03:42 PM   [ # 6 ]   [ Rating: 0 ]
Joined: 2012-02-23
2 posts
stubear - 13 February 2013 10:50 AM
Miles - 23 February 2012 04:19 PM

As of 2.1.0, you can accomplish this without extending the Email class…

Solution:
For TLS: $config[‘smtp_crypto’] = ‘tls’;
For SSL: $config[‘smtp_crypto’] = ‘ssl’;

Tested it today and it works great!

I’m running into this issue now. Has this config variable been confirmed? I’m still having trouble over all with getting Freeform (and by extension email sent through the Communicate tab in the CP) and I’m just trying to eliminate things like this so their Exchange Server admin can stop blaming EE and start looking into this from his end. I did have to hack the CI email library to overwrite the port (587 instead of 25) and I had to change the newline and crlf variables to /r/n instead of just /n. Anything else I might have missed? Any other changed to the CI email library that need to be made? Other hidden config variables that need to be set?

Stubear, which version of Codeigniter are you running?  The port and new line can be set in the config and do not need to be edited in the core files at all.

I’ve put an example of how I’m accomplishing the TLS on this pastebin link http://pastebin.com/pu9YiMfL

I hope this helps