Skip to content

Commit

Permalink
adding a tls option to SmtpTransport to support TLS SMTP servers like…
Browse files Browse the repository at this point in the history
… MS Exchange 2010
  • Loading branch information
steinkel committed Jul 21, 2012
1 parent 27a895d commit 55c9206
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
13 changes: 12 additions & 1 deletion lib/Cake/Network/Email/SmtpTransport.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public function config($config = array()) {
'timeout' => 30, 'timeout' => 30,
'username' => null, 'username' => null,
'password' => null, 'password' => null,
'client' => null 'client' => null,
'tls' => false
); );
$this->_config = $config + $default; $this->_config = $config + $default;
} }
Expand Down Expand Up @@ -107,7 +108,15 @@ protected function _connect() {


try { try {
$this->_smtpSend("EHLO {$host}", '250'); $this->_smtpSend("EHLO {$host}", '250');
if ($this->_config['tls']) {
$this->_smtpSend("STARTTLS", '220');
$this->_socket->enableCrypto('tls');
$this->_smtpSend("EHLO {$host}", '250');
}
} catch (SocketException $e) { } catch (SocketException $e) {
if ($this->_config['tls']) {
throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.'));
}
try { try {
$this->_smtpSend("HELO {$host}", '250'); $this->_smtpSend("HELO {$host}", '250');
} catch (SocketException $e2) { } catch (SocketException $e2) {
Expand All @@ -132,6 +141,8 @@ protected function _auth() {
if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) { if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) {
throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.')); throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.'));
} }
} elseif ($authRequired == '504') {
throw new SocketException(__d('cake_dev', 'SMTP authentication method not allowed, check if SMTP server requires TLS'));
} elseif ($authRequired != '503') { } elseif ($authRequired != '503') {
throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.')); throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.'));
} }
Expand Down
66 changes: 65 additions & 1 deletion lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class SmtpTransportTest extends CakeTestCase {
*/ */
public function setUp() { public function setUp() {
if (!class_exists('MockSocket')) { if (!class_exists('MockSocket')) {
$this->getMock('CakeSocket', array('read', 'write', 'connect'), array(), 'MockSocket'); $this->getMock('CakeSocket', array('read', 'write', 'connect', 'enableCrypto'), array(), 'MockSocket');
} }
$this->socket = new MockSocket(); $this->socket = new MockSocket();


Expand All @@ -105,6 +105,70 @@ public function testConnectEhlo() {
$this->SmtpTransport->connect(); $this->SmtpTransport->connect();
} }


/**
* testConnectEhloTls method
*
* @return void
*/
public function testConnectEhloTls() {
$this->SmtpTransport->config(array('tls' => true));
$this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
$this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
$this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
$this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
$this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n");
$this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(7))->method('read')->will($this->returnValue("220 Server ready\r\n"));
$this->socket->expects($this->at(8))->method('other')->with('tls')->will($this->returnValue(true));
$this->socket->expects($this->at(9))->method('write')->with("EHLO localhost\r\n");
$this->socket->expects($this->at(10))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(11))->method('read')->will($this->returnValue("250 Accepted\r\n"));
$this->SmtpTransport->connect();
}

/**
* testConnectEhloTlsOnNonTlsServer method
*
* @return void
*/
public function testConnectEhloTlsOnNonTlsServer() {
$this->SmtpTransport->config(array('tls' => true));
$this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
$this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
$this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
$this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
$this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n");
$this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(7))->method('read')->will($this->returnValue("500 5.3.3 Unrecognized command\r\n"));
$this->setExpectedException('SocketException');
$this->SmtpTransport->connect();
}

/**
* testConnectEhloNoTlsOnRequiredTlsServer method
*
* @return void
*/
public function testConnectEhloNoTlsOnRequiredTlsServer() {
$this->SmtpTransport->config(array('tls' => false, 'username' => 'user', 'password' => 'pass'));
$this->socket->expects($this->any())->method('connect')->will($this->returnValue(true));
$this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n"));
$this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n");
$this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n"));
$this->socket->expects($this->at(5))->method('read')->with("AUTH LOGIN\r\n");
$this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(7))->method('read')->will($this->returnValue("504 5.7.4 Unrecognized authentication type\r\n"));
$this->setExpectedException('SocketException');
$this->SmtpTransport->connect();
$this->SmtpTransport->auth();
}

/** /**
* testConnectHelo method * testConnectHelo method
* *
Expand Down

0 comments on commit 55c9206

Please sign in to comment.