1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
25: class Jyxo_Mail_Sender_Smtp
26: {
27: 28: 29: 30: 31:
32: const LINE_END = "\r\n";
33:
34: 35: 36: 37: 38:
39: private $connection = null;
40:
41: 42: 43: 44: 45:
46: private $host = 'localhost';
47:
48: 49: 50: 51: 52:
53: private $port = 25;
54:
55: 56: 57: 58: 59:
60: private $helo = 'localhost';
61:
62: 63: 64: 65: 66:
67: private $timeout = 5;
68:
69: 70: 71: 72: 73: 74: 75: 76:
77: public function __construct($host = 'localhost', $port = 25, $helo = 'localhost', $timeout = 5)
78: {
79: $this->host = (string) $host;
80: $this->port = (int) $port;
81: $this->timeout = (int) $timeout;
82: $this->helo = (string) $helo;
83: }
84:
85: 86: 87:
88: public function __destruct()
89: {
90: if (is_resource($this->connection)) {
91: $this->disconnect();
92: }
93: }
94:
95: 96: 97: 98: 99: 100:
101: public function connect()
102: {
103: $this->connection = fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
104: if (false === $this->connection) {
105: throw new Jyxo_Mail_Sender_SmtpException('CONNECTION: ' . $errno . ' ' . $errstr);
106: }
107:
108:
109: $this->readData();
110:
111:
112: $this->commandHelo();
113:
114: return $this;
115: }
116:
117: 118: 119: 120: 121:
122: public function disconnect()
123: {
124: if (is_resource($this->connection)) {
125: try {
126: $this->reset();
127: $this->writeData('QUIT');
128: fclose($this->connection);
129: $this->connection = null;
130: } catch (Exception $e) {
131:
132: }
133: }
134:
135: return $this;
136: }
137:
138: 139: 140: 141: 142: 143: 144: 145:
146: public function auth($user, $password)
147: {
148: $this->writeData('AUTH LOGIN');
149: $response = $this->readData();
150: if ('334' !== substr($response, 0, 3)) {
151: throw new Jyxo_Mail_Sender_SmtpException('AUTH: ' . $response);
152: }
153: $this->writeData(base64_encode($user));
154: $response = $this->readData();
155: if ('334' !== substr($response, 0, 3)) {
156: throw new Jyxo_Mail_Sender_SmtpException('AUTH: ' . $response);
157: }
158: $this->writeData(base64_encode($password));
159: $response = $this->readData();
160: if ('235' !== substr($response, 0, 3)) {
161: throw new Jyxo_Mail_Sender_SmtpException('AUTH: ' . $response);
162: }
163:
164: return $this;
165: }
166:
167: 168: 169: 170: 171: 172:
173: public function from($from)
174: {
175: $this->commandMailFrom($from);
176:
177: return $this;
178: }
179:
180: 181: 182: 183: 184: 185:
186: public function recipient($recipient)
187: {
188: $this->commandRcptTo($recipient);
189:
190: return $this;
191: }
192:
193: 194: 195: 196: 197: 198: 199: 200:
201: public function data($header, $body)
202: {
203: $lineEnds = array(Jyxo_Mail_Sender::LINE_END . '.' => self::LINE_END . '..', Jyxo_Mail_Sender::LINE_END => self::LINE_END);
204: $header = strtr($header, $lineEnds);
205: $body = strtr($body, $lineEnds);
206: if ('.' == $body[0]) {
207: $body = '.' . $body;
208: }
209:
210: $this->commandData();
211: $this->writeData(trim($header));
212: $this->writeData('');
213: $this->writeData($body);
214: $this->writeData('.');
215:
216: $response = $this->readData();
217: if ('250' !== substr($response, 0, 3)) {
218: throw new Jyxo_Mail_Sender_SmtpException('SEND: ' . $response);
219: }
220:
221: return $this;
222: }
223:
224: 225: 226: 227: 228:
229: public function reset()
230: {
231: $this->commandRset();
232:
233: return $this;
234: }
235:
236: 237: 238: 239: 240:
241: private function commandHelo()
242: {
243: $this->writeData('EHLO ' . $this->helo);
244: $response = $this->readData();
245: if ('250' !== substr($response, 0, 3)) {
246: $this->writeData('HELO ' . $this->helo);
247: $response = $this->readData();
248: if ('250' !== substr($response, 0, 3)) {
249: throw new Jyxo_Mail_Sender_SmtpException('HELO: ' . $response);
250: }
251: }
252: }
253:
254: 255: 256: 257: 258: 259:
260: private function commandMailFrom($from)
261: {
262: $this->writeData('MAIL FROM: <' . $from . '>');
263: $response = $this->readData();
264: if ('250' !== substr($response, 0, 3)) {
265: throw new Jyxo_Mail_Sender_SmtpException('MAIL FROM: ' . $response);
266: }
267: }
268:
269: 270: 271: 272: 273: 274:
275: private function commandRcptTo($recipient)
276: {
277: $this->writeData('RCPT TO: <' . $recipient . '>');
278: $response = $this->readData();
279: if ('250' !== substr($response, 0, 3)) {
280: throw new Jyxo_Mail_Sender_SmtpException('RCPT TO: ' . $response);
281: }
282: }
283:
284: 285: 286: 287: 288:
289: private function commandData()
290: {
291: $this->writeData('DATA');
292: $response = $this->readData();
293: if ('354' !== substr($response, 0, 3)) {
294: throw new Jyxo_Mail_Sender_SmtpException('DATA: ' . $response);
295: }
296: }
297:
298: 299: 300: 301: 302:
303: private function commandRset()
304: {
305: $this->writeData('RSET');
306: $response = $this->readData();
307: if ('250' !== substr($response, 0, 3)) {
308: throw new Jyxo_Mail_Sender_SmtpException('RSET: ' . $response);
309: }
310: }
311:
312: 313: 314: 315: 316:
317: private function readData()
318: {
319: $data = '';
320: $i = 0;
321: while ($line = fgets($this->connection)) {
322: $data .= $line;
323: if (' ' == substr($line, 3, 1)) {
324: break;
325: }
326: }
327: return $data;
328: }
329:
330: 331: 332: 333: 334: 335:
336: private function writeData($data)
337: {
338: if (!fwrite($this->connection, $data . self::LINE_END)) {
339: throw new Jyxo_Mail_Sender_SmtpException('Error while writing data.');
340: }
341: }
342: }
343: