Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13532 anikendra 1
<?php
2
/**
3
 * Send mail using SMTP protocol
4
 *
5
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://cakephp.org CakePHP(tm) Project
14
 * @package       Cake.Network.Email
15
 * @since         CakePHP(tm) v 2.0.0
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18
 
19
App::uses('CakeSocket', 'Network');
20
 
21
/**
22
 * Send mail using SMTP protocol
23
 *
24
 * @package       Cake.Network.Email
25
 */
26
class SmtpTransport extends AbstractTransport {
27
 
28
/**
29
 * Socket to SMTP server
30
 *
31
 * @var CakeSocket
32
 */
33
	protected $_socket;
34
 
35
/**
36
 * CakeEmail
37
 *
38
 * @var CakeEmail
39
 */
40
	protected $_cakeEmail;
41
 
42
/**
43
 * Content of email to return
44
 *
45
 * @var string
46
 */
47
	protected $_content;
48
 
49
/**
50
 * Send mail
51
 *
52
 * @param CakeEmail $email CakeEmail
53
 * @return array
54
 * @throws SocketException
55
 */
56
	public function send(CakeEmail $email) {
57
		$this->_cakeEmail = $email;
58
 
59
		$this->_connect();
60
		$this->_auth();
61
		$this->_sendRcpt();
62
		$this->_sendData();
63
		$this->_disconnect();
64
 
65
		return $this->_content;
66
	}
67
 
68
/**
69
 * Set the configuration
70
 *
71
 * @param array $config
72
 * @return array Returns configs
73
 */
74
	public function config($config = null) {
75
		if ($config === null) {
76
			return $this->_config;
77
		}
78
		$default = array(
79
			'host' => 'localhost',
80
			'port' => 25,
81
			'timeout' => 30,
82
			'username' => null,
83
			'password' => null,
84
			'client' => null,
85
			'tls' => false
86
		);
87
		$this->_config = array_merge($default, $this->_config, $config);
88
		return $this->_config;
89
	}
90
 
91
/**
92
 * Connect to SMTP Server
93
 *
94
 * @return void
95
 * @throws SocketException
96
 */
97
	protected function _connect() {
98
		$this->_generateSocket();
99
		if (!$this->_socket->connect()) {
100
			throw new SocketException(__d('cake_dev', 'Unable to connect to SMTP server.'));
101
		}
102
		$this->_smtpSend(null, '220');
103
 
104
		if (isset($this->_config['client'])) {
105
			$host = $this->_config['client'];
106
		} elseif ($httpHost = env('HTTP_HOST')) {
107
			list($host) = explode(':', $httpHost);
108
		} else {
109
			$host = 'localhost';
110
		}
111
 
112
		try {
113
			$this->_smtpSend("EHLO {$host}", '250');
114
			if ($this->_config['tls']) {
115
				$this->_smtpSend("STARTTLS", '220');
116
				$this->_socket->enableCrypto('tls');
117
				$this->_smtpSend("EHLO {$host}", '250');
118
			}
119
		} catch (SocketException $e) {
120
			if ($this->_config['tls']) {
121
				throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.'));
122
			}
123
			try {
124
				$this->_smtpSend("HELO {$host}", '250');
125
			} catch (SocketException $e2) {
126
				throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection.'));
127
			}
128
		}
129
	}
130
 
131
/**
132
 * Send authentication
133
 *
134
 * @return void
135
 * @throws SocketException
136
 */
137
	protected function _auth() {
138
		if (isset($this->_config['username']) && isset($this->_config['password'])) {
139
			$authRequired = $this->_smtpSend('AUTH LOGIN', '334|503');
140
			if ($authRequired == '334') {
141
				if (!$this->_smtpSend(base64_encode($this->_config['username']), '334')) {
142
					throw new SocketException(__d('cake_dev', 'SMTP server did not accept the username.'));
143
				}
144
				if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) {
145
					throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.'));
146
				}
147
			} elseif ($authRequired == '504') {
148
				throw new SocketException(__d('cake_dev', 'SMTP authentication method not allowed, check if SMTP server requires TLS'));
149
			} elseif ($authRequired != '503') {
150
				throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.'));
151
			}
152
		}
153
	}
154
 
155
/**
156
 * Send emails
157
 *
158
 * @return void
159
 * @throws SocketException
160
 */
161
	protected function _sendRcpt() {
162
		$from = $this->_cakeEmail->returnPath();
163
		if (empty($from)) {
164
			$from = $this->_cakeEmail->from();
165
		}
166
		$this->_smtpSend('MAIL FROM:<' . key($from) . '>');
167
 
168
		$to = $this->_cakeEmail->to();
169
		$cc = $this->_cakeEmail->cc();
170
		$bcc = $this->_cakeEmail->bcc();
171
		$emails = array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
172
		foreach ($emails as $email) {
173
			$this->_smtpSend('RCPT TO:<' . $email . '>');
174
		}
175
	}
176
 
177
/**
178
 * Send Data
179
 *
180
 * @return void
181
 * @throws SocketException
182
 */
183
	protected function _sendData() {
184
		$this->_smtpSend('DATA', '354');
185
 
186
		$headers = $this->_cakeEmail->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject'));
187
		$headers = $this->_headersToString($headers);
188
		$lines = $this->_cakeEmail->message();
189
		$messages = array();
190
		foreach ($lines as $line) {
191
			if ((!empty($line)) && ($line[0] === '.')) {
192
				$messages[] = '.' . $line;
193
			} else {
194
				$messages[] = $line;
195
			}
196
		}
197
		$message = implode("\r\n", $messages);
198
		$this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
199
		$this->_content = array('headers' => $headers, 'message' => $message);
200
	}
201
 
202
/**
203
 * Disconnect
204
 *
205
 * @return void
206
 * @throws SocketException
207
 */
208
	protected function _disconnect() {
209
		$this->_smtpSend('QUIT', false);
210
		$this->_socket->disconnect();
211
	}
212
 
213
/**
214
 * Helper method to generate socket
215
 *
216
 * @return void
217
 * @throws SocketException
218
 */
219
	protected function _generateSocket() {
220
		$this->_socket = new CakeSocket($this->_config);
221
	}
222
 
223
/**
224
 * Protected method for sending data to SMTP connection
225
 *
226
 * @param string $data data to be sent to SMTP server
227
 * @param string|boolean $checkCode code to check for in server response, false to skip
228
 * @return void
229
 * @throws SocketException
230
 */
231
	protected function _smtpSend($data, $checkCode = '250') {
232
		if ($data !== null) {
233
			$this->_socket->write($data . "\r\n");
234
		}
235
		while ($checkCode !== false) {
236
			$response = '';
237
			$startTime = time();
238
			while (substr($response, -2) !== "\r\n" && ((time() - $startTime) < $this->_config['timeout'])) {
239
				$response .= $this->_socket->read();
240
			}
241
			if (substr($response, -2) !== "\r\n") {
242
				throw new SocketException(__d('cake_dev', 'SMTP timeout.'));
243
			}
244
			$responseLines = explode("\r\n", rtrim($response, "\r\n"));
245
			$response = end($responseLines);
246
 
247
			if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
248
				if ($code[2] === '-') {
249
					continue;
250
				}
251
				return $code[1];
252
			}
253
			throw new SocketException(__d('cake_dev', 'SMTP Error: %s', $response));
254
		}
255
	}
256
 
257
}