xref: /plugin/smtp/vendor/txthinking/mailer/src/Mailer/SMTP.php (revision 28d0809a4424b7a71eb621f24d1b3a19c5927170)
1ee5c0205SAndreas Gohr<?php
2ee5c0205SAndreas Gohr/***************************************************\
3ee5c0205SAndreas Gohr *
4ee5c0205SAndreas Gohr *  Mailer (https://github.com/txthinking/Mailer)
5ee5c0205SAndreas Gohr *
6ee5c0205SAndreas Gohr *  A lightweight PHP SMTP mail sender.
7ee5c0205SAndreas Gohr *  Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
8ee5c0205SAndreas Gohr *
9ee5c0205SAndreas Gohr *  Support html body, don't worry that the receiver's
10ee5c0205SAndreas Gohr *  mail client can't support html, because Mailer will
11ee5c0205SAndreas Gohr *  send both text/plain and text/html body, so if the
12ee5c0205SAndreas Gohr *  mail client can't support html, it will display the
13ee5c0205SAndreas Gohr *  text/plain body.
14ee5c0205SAndreas Gohr *
15ee5c0205SAndreas Gohr *  Create Date 2012-07-25.
16ee5c0205SAndreas Gohr *  Under the MIT license.
17ee5c0205SAndreas Gohr *
18ee5c0205SAndreas Gohr \***************************************************/
19ee5c0205SAndreas Gohr
20ee5c0205SAndreas Gohrnamespace Tx\Mailer;
21ee5c0205SAndreas Gohr
22ee5c0205SAndreas Gohruse Psr\Log\LoggerInterface;
23ee5c0205SAndreas Gohruse Tx\Mailer\Exceptions\CodeException;
24ee5c0205SAndreas Gohruse Tx\Mailer\Exceptions\CryptoException;
25ee5c0205SAndreas Gohruse Tx\Mailer\Exceptions\SMTPException;
26ee5c0205SAndreas Gohr
27ee5c0205SAndreas Gohrclass SMTP
28ee5c0205SAndreas Gohr{
29ee5c0205SAndreas Gohr    /**
30ee5c0205SAndreas Gohr     * smtp socket
31ee5c0205SAndreas Gohr     */
32ee5c0205SAndreas Gohr    protected $smtp;
33ee5c0205SAndreas Gohr
34ee5c0205SAndreas Gohr    /**
35ee5c0205SAndreas Gohr     * smtp server
36ee5c0205SAndreas Gohr     */
37ee5c0205SAndreas Gohr    protected $host;
38ee5c0205SAndreas Gohr
39ee5c0205SAndreas Gohr    /**
40ee5c0205SAndreas Gohr     * smtp server port
41ee5c0205SAndreas Gohr     */
42ee5c0205SAndreas Gohr    protected $port;
43ee5c0205SAndreas Gohr
44ee5c0205SAndreas Gohr    /**
45ee5c0205SAndreas Gohr     * smtp secure ssl tls tlsv1.0 tlsv1.1 tlsv1.2
46ee5c0205SAndreas Gohr     */
47ee5c0205SAndreas Gohr    protected $secure;
48ee5c0205SAndreas Gohr
49ee5c0205SAndreas Gohr    /**
50*28d0809aSAndreas Gohr     * smtp allow insecure ssl
51*28d0809aSAndreas Gohr     */
52*28d0809aSAndreas Gohr    protected $allowInsecure;
53*28d0809aSAndreas Gohr
54*28d0809aSAndreas Gohr    /**
55ee5c0205SAndreas Gohr     * EHLO message
56ee5c0205SAndreas Gohr     */
57ee5c0205SAndreas Gohr    protected $ehlo;
58ee5c0205SAndreas Gohr
59ee5c0205SAndreas Gohr    /**
60ee5c0205SAndreas Gohr     * smtp username
61ee5c0205SAndreas Gohr     */
62ee5c0205SAndreas Gohr    protected $username;
63ee5c0205SAndreas Gohr
64ee5c0205SAndreas Gohr    /**
65ee5c0205SAndreas Gohr     * smtp password
66ee5c0205SAndreas Gohr     */
67ee5c0205SAndreas Gohr    protected $password;
68ee5c0205SAndreas Gohr
69ee5c0205SAndreas Gohr    /**
70ee5c0205SAndreas Gohr     * oauth access token
71ee5c0205SAndreas Gohr     */
72ee5c0205SAndreas Gohr    protected $oauthToken;
73ee5c0205SAndreas Gohr
74ee5c0205SAndreas Gohr    /**
75ee5c0205SAndreas Gohr     * $this->CRLF
76ee5c0205SAndreas Gohr     * @var string
77ee5c0205SAndreas Gohr     */
78ee5c0205SAndreas Gohr    protected $CRLF = "\r\n";
79ee5c0205SAndreas Gohr
80ee5c0205SAndreas Gohr    /**
81ee5c0205SAndreas Gohr     * @var Message
82ee5c0205SAndreas Gohr     */
83ee5c0205SAndreas Gohr    protected $message;
84ee5c0205SAndreas Gohr
85ee5c0205SAndreas Gohr    /**
86ee5c0205SAndreas Gohr     * @var LoggerInterface - Used to make things prettier than self::$logger
87ee5c0205SAndreas Gohr     */
88ee5c0205SAndreas Gohr    protected $logger;
89ee5c0205SAndreas Gohr
90ee5c0205SAndreas Gohr    /**
91ee5c0205SAndreas Gohr     * Stack of all commands issued to SMTP
92ee5c0205SAndreas Gohr     * @var array
93ee5c0205SAndreas Gohr     */
94ee5c0205SAndreas Gohr    protected $commandStack = array();
95ee5c0205SAndreas Gohr
96ee5c0205SAndreas Gohr    /**
97ee5c0205SAndreas Gohr     * Stack of all results issued to SMTP
98ee5c0205SAndreas Gohr     * @var array
99ee5c0205SAndreas Gohr     */
100ee5c0205SAndreas Gohr    protected $resultStack = array();
101ee5c0205SAndreas Gohr
102ee5c0205SAndreas Gohr    public function __construct(LoggerInterface $logger=null)
103ee5c0205SAndreas Gohr    {
104ee5c0205SAndreas Gohr        $this->logger = $logger;
105ee5c0205SAndreas Gohr    }
106ee5c0205SAndreas Gohr
107ee5c0205SAndreas Gohr    /**
108ee5c0205SAndreas Gohr     * set server and port
109ee5c0205SAndreas Gohr     * @param string $host server
110ee5c0205SAndreas Gohr     * @param int $port port
111*28d0809aSAndreas Gohr     * @param string $secure ssl tls
112*28d0809aSAndreas Gohr     * @param bool $allowInsecure skip certificate verification?
113ee5c0205SAndreas Gohr     * @return $this
114ee5c0205SAndreas Gohr     */
115*28d0809aSAndreas Gohr    public function setServer($host, $port, $secure=null, $allowInsecure=null)
116ee5c0205SAndreas Gohr    {
117ee5c0205SAndreas Gohr        $this->host = $host;
118ee5c0205SAndreas Gohr        $this->port = $port;
119ee5c0205SAndreas Gohr        $this->secure = $secure;
120*28d0809aSAndreas Gohr        $this->allowInsecure = (bool) $allowInsecure;
121ee5c0205SAndreas Gohr        if(!$this->ehlo) $this->ehlo = $host;
122ee5c0205SAndreas Gohr        $this->logger && $this->logger->debug("Set: the server");
123ee5c0205SAndreas Gohr        return $this;
124ee5c0205SAndreas Gohr    }
125ee5c0205SAndreas Gohr
126ee5c0205SAndreas Gohr    /**
127ee5c0205SAndreas Gohr     * auth login with server
128ee5c0205SAndreas Gohr     * @param string $username
129ee5c0205SAndreas Gohr     * @param string $password
130ee5c0205SAndreas Gohr     * @return $this
131ee5c0205SAndreas Gohr     */
132ee5c0205SAndreas Gohr    public function setAuth($username, $password)
133ee5c0205SAndreas Gohr    {
134ee5c0205SAndreas Gohr        $this->username = $username;
135ee5c0205SAndreas Gohr        $this->password = $password;
136ee5c0205SAndreas Gohr        $this->logger && $this->logger->debug("Set: the auth login");
137ee5c0205SAndreas Gohr        return $this;
138ee5c0205SAndreas Gohr    }
139ee5c0205SAndreas Gohr
140ee5c0205SAndreas Gohr    /**
141ee5c0205SAndreas Gohr     * auth oauthbearer with server
142ee5c0205SAndreas Gohr     * @param string $accessToken
143ee5c0205SAndreas Gohr     * @return $this
144ee5c0205SAndreas Gohr     */
145ee5c0205SAndreas Gohr    public function setOAuth($accessToken)
146ee5c0205SAndreas Gohr    {
147ee5c0205SAndreas Gohr        $this->oauthToken = $accessToken;
148ee5c0205SAndreas Gohr        $this->logger && $this->logger->debug("Set: the auth oauthbearer");
149ee5c0205SAndreas Gohr        return $this;
150ee5c0205SAndreas Gohr    }
151ee5c0205SAndreas Gohr
152ee5c0205SAndreas Gohr    /**
153ee5c0205SAndreas Gohr     * set the EHLO message
154ee5c0205SAndreas Gohr     * @param $ehlo
155ee5c0205SAndreas Gohr     * @return $this
156ee5c0205SAndreas Gohr     */
157ee5c0205SAndreas Gohr    public function setEhlo($ehlo)
158ee5c0205SAndreas Gohr    {
159ee5c0205SAndreas Gohr        $this->ehlo = $ehlo;
160ee5c0205SAndreas Gohr        return $this;
161ee5c0205SAndreas Gohr    }
162ee5c0205SAndreas Gohr
163ee5c0205SAndreas Gohr    /**
164ee5c0205SAndreas Gohr     * Send the message
165ee5c0205SAndreas Gohr     *
166ee5c0205SAndreas Gohr     * @param Message $message
167ee5c0205SAndreas Gohr     * @return bool
168ee5c0205SAndreas Gohr     * @throws CodeException
169ee5c0205SAndreas Gohr     * @throws CryptoException
170ee5c0205SAndreas Gohr     * @throws SMTPException
171ee5c0205SAndreas Gohr     */
172ee5c0205SAndreas Gohr    public function send(Message $message)
173ee5c0205SAndreas Gohr    {
174ee5c0205SAndreas Gohr        $this->logger && $this->logger->debug('Set: a message will be sent');
175ee5c0205SAndreas Gohr        $this->message = $message;
176ee5c0205SAndreas Gohr        $this->connect()
177ee5c0205SAndreas Gohr            ->ehlo();
178ee5c0205SAndreas Gohr
179ee5c0205SAndreas Gohr        if ($this->secure === 'tls' || $this->secure === 'tlsv1.0' || $this->secure === 'tlsv1.1' | $this->secure === 'tlsv1.2') {
180ee5c0205SAndreas Gohr            $this->starttls()
181ee5c0205SAndreas Gohr                ->ehlo();
182ee5c0205SAndreas Gohr        }
183ee5c0205SAndreas Gohr
184ee5c0205SAndreas Gohr        if ($this->username !== null || $this->password !== null) {
185ee5c0205SAndreas Gohr            $this->authLogin();
186ee5c0205SAndreas Gohr        } elseif ($this->oauthToken !== null) {
187ee5c0205SAndreas Gohr            $this->authOAuthBearer();
188ee5c0205SAndreas Gohr        }
189ee5c0205SAndreas Gohr        $this->mailFrom()
190ee5c0205SAndreas Gohr            ->rcptTo()
191ee5c0205SAndreas Gohr            ->data()
192ee5c0205SAndreas Gohr            ->quit();
193ee5c0205SAndreas Gohr        return fclose($this->smtp);
194ee5c0205SAndreas Gohr    }
195ee5c0205SAndreas Gohr
196ee5c0205SAndreas Gohr    /**
197ee5c0205SAndreas Gohr     * connect the server
198ee5c0205SAndreas Gohr     * SUCCESS 220
199ee5c0205SAndreas Gohr     * @return $this
200ee5c0205SAndreas Gohr     * @throws CodeException
201ee5c0205SAndreas Gohr     * @throws SMTPException
202ee5c0205SAndreas Gohr     */
203ee5c0205SAndreas Gohr    protected function connect()
204ee5c0205SAndreas Gohr    {
205ee5c0205SAndreas Gohr        $this->logger && $this->logger->debug("Connecting to {$this->host} at {$this->port}");
206ee5c0205SAndreas Gohr        $host = ($this->secure == 'ssl') ? 'ssl://' . $this->host : $this->host;
207*28d0809aSAndreas Gohr        // Create connection
208*28d0809aSAndreas Gohr        $context = stream_context_create([]);
209*28d0809aSAndreas Gohr        if ($this->allowInsecure) {
210*28d0809aSAndreas Gohr            $context = stream_context_create([
211*28d0809aSAndreas Gohr                'ssl' => [
212*28d0809aSAndreas Gohr                    'security_level' => 0,
213*28d0809aSAndreas Gohr                    'verify_peer' => false,
214*28d0809aSAndreas Gohr                    'verify_peer_name' => false
215*28d0809aSAndreas Gohr                ]
216*28d0809aSAndreas Gohr            ]);
217*28d0809aSAndreas Gohr        }
218*28d0809aSAndreas Gohr        $this->smtp = @stream_socket_client(
219*28d0809aSAndreas Gohr            $host.':'.$this->port,
220*28d0809aSAndreas Gohr            $error_code,
221*28d0809aSAndreas Gohr            $error_message,
222*28d0809aSAndreas Gohr            ini_get('default_socket_timeout'),
223*28d0809aSAndreas Gohr            STREAM_CLIENT_CONNECT,
224*28d0809aSAndreas Gohr            $context
225*28d0809aSAndreas Gohr        );
226ee5c0205SAndreas Gohr        if (!$this->smtp){
227*28d0809aSAndreas Gohr            throw new SMTPException("Could not open SMTP Port to $host:{$this->port}");
228ee5c0205SAndreas Gohr        }
229ee5c0205SAndreas Gohr        $code = $this->getCode();
230ee5c0205SAndreas Gohr        if ($code !== '220'){
231ee5c0205SAndreas Gohr            throw new CodeException('220', $code, array_pop($this->resultStack));
232ee5c0205SAndreas Gohr        }
233ee5c0205SAndreas Gohr        return $this;
234ee5c0205SAndreas Gohr    }
235ee5c0205SAndreas Gohr
236ee5c0205SAndreas Gohr    /**
237ee5c0205SAndreas Gohr     * SMTP STARTTLS
238ee5c0205SAndreas Gohr     * SUCCESS 220
239ee5c0205SAndreas Gohr     * @return $this
240ee5c0205SAndreas Gohr     * @throws CodeException
241ee5c0205SAndreas Gohr     * @throws CryptoException
242ee5c0205SAndreas Gohr     * @throws SMTPException
243ee5c0205SAndreas Gohr     */
244ee5c0205SAndreas Gohr    protected function starttls()
245ee5c0205SAndreas Gohr    {
246ee5c0205SAndreas Gohr        $in = "STARTTLS" . $this->CRLF;
247ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
248ee5c0205SAndreas Gohr        if ($code !== '220'){
249ee5c0205SAndreas Gohr            throw new CodeException('220', $code, array_pop($this->resultStack));
250ee5c0205SAndreas Gohr        }
251ee5c0205SAndreas Gohr
252ee5c0205SAndreas Gohr        if ($this->secure !== 'tls' && version_compare(phpversion(), '5.6.0', '<')) {
253ee5c0205SAndreas Gohr            throw new CryptoException('Crypto type expected PHP 5.6 or greater');
254ee5c0205SAndreas Gohr        }
255ee5c0205SAndreas Gohr
256*28d0809aSAndreas Gohr        if ($this->allowInsecure) {
257*28d0809aSAndreas Gohr            stream_context_set_option($this->smtp, 'ssl', 'verify_peer', false);
258*28d0809aSAndreas Gohr            stream_context_set_option($this->smtp, 'ssl', 'verify_peer_name', false);
259*28d0809aSAndreas Gohr            stream_context_set_option($this->smtp, 'ssl', 'allow_self_signed', true);
260ee5c0205SAndreas Gohr        }
261ee5c0205SAndreas Gohr
262*28d0809aSAndreas Gohr        if(!\stream_socket_enable_crypto($this->smtp, true, STREAM_CRYPTO_METHOD_ANY_CLIENT)) {
263ee5c0205SAndreas Gohr            throw new CryptoException("Start TLS failed to enable crypto");
264ee5c0205SAndreas Gohr        }
265ee5c0205SAndreas Gohr        return $this;
266ee5c0205SAndreas Gohr    }
267ee5c0205SAndreas Gohr
268ee5c0205SAndreas Gohr    /**
269ee5c0205SAndreas Gohr     * SMTP EHLO
270ee5c0205SAndreas Gohr     * SUCCESS 250
271ee5c0205SAndreas Gohr     * @return $this
272ee5c0205SAndreas Gohr     * @throws CodeException
273ee5c0205SAndreas Gohr     * @throws SMTPException
274ee5c0205SAndreas Gohr     */
275ee5c0205SAndreas Gohr    protected function ehlo()
276ee5c0205SAndreas Gohr    {
277ee5c0205SAndreas Gohr        $in = "EHLO " . $this->ehlo . $this->CRLF;
278ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
279ee5c0205SAndreas Gohr        if ($code !== '250'){
280ee5c0205SAndreas Gohr            throw new CodeException('250', $code, array_pop($this->resultStack));
281ee5c0205SAndreas Gohr        }
282ee5c0205SAndreas Gohr        return $this;
283ee5c0205SAndreas Gohr    }
284ee5c0205SAndreas Gohr
285ee5c0205SAndreas Gohr    /**
286ee5c0205SAndreas Gohr     * SMTP AUTH LOGIN
287ee5c0205SAndreas Gohr     * SUCCESS 334
288ee5c0205SAndreas Gohr     * SUCCESS 334
289ee5c0205SAndreas Gohr     * SUCCESS 235
290ee5c0205SAndreas Gohr     * @return $this
291ee5c0205SAndreas Gohr     * @throws CodeException
292ee5c0205SAndreas Gohr     * @throws SMTPException
293ee5c0205SAndreas Gohr     */
294ee5c0205SAndreas Gohr    protected function authLogin()
295ee5c0205SAndreas Gohr    {
296ee5c0205SAndreas Gohr        $in = "AUTH LOGIN" . $this->CRLF;
297ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
298ee5c0205SAndreas Gohr        if ($code !== '334'){
299ee5c0205SAndreas Gohr            throw new CodeException('334', $code, array_pop($this->resultStack));
300ee5c0205SAndreas Gohr        }
301ee5c0205SAndreas Gohr        $in = base64_encode($this->username) . $this->CRLF;
302ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
303ee5c0205SAndreas Gohr        if ($code !== '334'){
304ee5c0205SAndreas Gohr            throw new CodeException('334', $code, array_pop($this->resultStack));
305ee5c0205SAndreas Gohr        }
306ee5c0205SAndreas Gohr        $in = base64_encode($this->password) . $this->CRLF;
307ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
308ee5c0205SAndreas Gohr        if ($code !== '235'){
309ee5c0205SAndreas Gohr            throw new CodeException('235', $code, array_pop($this->resultStack));
310ee5c0205SAndreas Gohr        }
311ee5c0205SAndreas Gohr        return $this;
312ee5c0205SAndreas Gohr    }
313ee5c0205SAndreas Gohr
314ee5c0205SAndreas Gohr    /**
315ee5c0205SAndreas Gohr     * SMTP AUTH OAUTHBEARER
316ee5c0205SAndreas Gohr     * SUCCESS 235
317ee5c0205SAndreas Gohr     * @return $this
318ee5c0205SAndreas Gohr     * @throws CodeException
319ee5c0205SAndreas Gohr     * @throws SMTPException
320ee5c0205SAndreas Gohr     */
321ee5c0205SAndreas Gohr    protected function authOAuthBearer()
322ee5c0205SAndreas Gohr    {
323ee5c0205SAndreas Gohr        $authStr = sprintf("n,a=%s,%shost=%s%sport=%s%sauth=Bearer %s%s%s",
324ee5c0205SAndreas Gohr            $this->message->getFromEmail(),
325ee5c0205SAndreas Gohr            chr(1),
326ee5c0205SAndreas Gohr            $this->host,
327ee5c0205SAndreas Gohr            chr(1),
328ee5c0205SAndreas Gohr            $this->port,
329ee5c0205SAndreas Gohr            chr(1),
330ee5c0205SAndreas Gohr            $this->oauthToken,
331ee5c0205SAndreas Gohr            chr(1),
332ee5c0205SAndreas Gohr            chr(1)
333ee5c0205SAndreas Gohr        );
334ee5c0205SAndreas Gohr        $authStr = base64_encode($authStr);
335ee5c0205SAndreas Gohr        $in = "AUTH OAUTHBEARER $authStr" . $this->CRLF;
336ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
337ee5c0205SAndreas Gohr        if ($code !== '235'){
338ee5c0205SAndreas Gohr            throw new CodeException('235', $code, array_pop($this->resultStack));
339ee5c0205SAndreas Gohr        }
340ee5c0205SAndreas Gohr        return $this;
341ee5c0205SAndreas Gohr    }
342ee5c0205SAndreas Gohr
343ee5c0205SAndreas Gohr    /**
344ee5c0205SAndreas Gohr     * SMTP AUTH XOAUTH2
345ee5c0205SAndreas Gohr     * SUCCESS 235
346ee5c0205SAndreas Gohr     * @return $this
347ee5c0205SAndreas Gohr     * @throws CodeException
348ee5c0205SAndreas Gohr     * @throws SMTPException
349ee5c0205SAndreas Gohr     */
350ee5c0205SAndreas Gohr    protected function authXOAuth2()
351ee5c0205SAndreas Gohr    {
352ee5c0205SAndreas Gohr        $authStr = sprintf("user=%s%sauth=Bearer %s%s%s",
353ee5c0205SAndreas Gohr            $this->message->getFromEmail(),
354ee5c0205SAndreas Gohr            chr(1),
355ee5c0205SAndreas Gohr            $this->oauthToken,
356ee5c0205SAndreas Gohr            chr(1),
357ee5c0205SAndreas Gohr            chr(1)
358ee5c0205SAndreas Gohr        );
359ee5c0205SAndreas Gohr        $authStr = base64_encode($authStr);
360ee5c0205SAndreas Gohr        $in = "AUTH XOAUTH2 $authStr" . $this->CRLF;
361ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
362ee5c0205SAndreas Gohr        if ($code !== '235'){
363ee5c0205SAndreas Gohr            throw new CodeException('235', $code, array_pop($this->resultStack));
364ee5c0205SAndreas Gohr        }
365ee5c0205SAndreas Gohr        return $this;
366ee5c0205SAndreas Gohr    }
367ee5c0205SAndreas Gohr
368ee5c0205SAndreas Gohr    /**
369ee5c0205SAndreas Gohr     * SMTP MAIL FROM
370ee5c0205SAndreas Gohr     * SUCCESS 250
371ee5c0205SAndreas Gohr     * @return $this
372ee5c0205SAndreas Gohr     * @throws CodeException
373ee5c0205SAndreas Gohr     * @throws SMTPException
374ee5c0205SAndreas Gohr     */
375ee5c0205SAndreas Gohr    protected function mailFrom()
376ee5c0205SAndreas Gohr    {
377ee5c0205SAndreas Gohr        $in = "MAIL FROM:<{$this->message->getFromEmail()}>" . $this->CRLF;
378ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
379ee5c0205SAndreas Gohr        if ($code !== '250') {
380ee5c0205SAndreas Gohr            throw new CodeException('250', $code, array_pop($this->resultStack));
381ee5c0205SAndreas Gohr        }
382ee5c0205SAndreas Gohr        return $this;
383ee5c0205SAndreas Gohr    }
384ee5c0205SAndreas Gohr
385ee5c0205SAndreas Gohr    /**
386ee5c0205SAndreas Gohr     * SMTP RCPT TO
387ee5c0205SAndreas Gohr     * SUCCESS 250
388ee5c0205SAndreas Gohr     * @return $this
389ee5c0205SAndreas Gohr     * @throws CodeException
390ee5c0205SAndreas Gohr     * @throws SMTPException
391ee5c0205SAndreas Gohr     */
392ee5c0205SAndreas Gohr    protected function rcptTo()
393ee5c0205SAndreas Gohr    {
394ee5c0205SAndreas Gohr        $to = array_merge(
395ee5c0205SAndreas Gohr            $this->message->getTo(),
396ee5c0205SAndreas Gohr            $this->message->getCc(),
397ee5c0205SAndreas Gohr            $this->message->getBcc()
398ee5c0205SAndreas Gohr        );
399ee5c0205SAndreas Gohr        foreach ($to as $toEmail=>$_) {
400ee5c0205SAndreas Gohr            $in = "RCPT TO:<" . $toEmail . ">" . $this->CRLF;
401ee5c0205SAndreas Gohr            $code = $this->pushStack($in);
402ee5c0205SAndreas Gohr            if ($code !== '250') {
403ee5c0205SAndreas Gohr                throw new CodeException('250', $code, array_pop($this->resultStack));
404ee5c0205SAndreas Gohr            }
405ee5c0205SAndreas Gohr        }
406ee5c0205SAndreas Gohr        return $this;
407ee5c0205SAndreas Gohr    }
408ee5c0205SAndreas Gohr
409ee5c0205SAndreas Gohr    /**
410ee5c0205SAndreas Gohr     * SMTP DATA
411ee5c0205SAndreas Gohr     * SUCCESS 354
412ee5c0205SAndreas Gohr     * SUCCESS 250
413ee5c0205SAndreas Gohr     * @return $this
414ee5c0205SAndreas Gohr     * @throws CodeException
415ee5c0205SAndreas Gohr     * @throws SMTPException
416ee5c0205SAndreas Gohr     */
417ee5c0205SAndreas Gohr    protected function data()
418ee5c0205SAndreas Gohr    {
419ee5c0205SAndreas Gohr        $in = "DATA" . $this->CRLF;
420ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
421ee5c0205SAndreas Gohr        if ($code !== '354') {
422ee5c0205SAndreas Gohr            throw new CodeException('354', $code, array_pop($this->resultStack));
423ee5c0205SAndreas Gohr        }
424ee5c0205SAndreas Gohr        $in = $this->message->toString();
425ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
426ee5c0205SAndreas Gohr        if ($code !== '250'){
427ee5c0205SAndreas Gohr            throw new CodeException('250', $code, array_pop($this->resultStack));
428ee5c0205SAndreas Gohr        }
429ee5c0205SAndreas Gohr        return $this;
430ee5c0205SAndreas Gohr    }
431ee5c0205SAndreas Gohr
432ee5c0205SAndreas Gohr    /**
433ee5c0205SAndreas Gohr     * SMTP QUIT
434ee5c0205SAndreas Gohr     * SUCCESS 221
435ee5c0205SAndreas Gohr     * @return $this
436ee5c0205SAndreas Gohr     * @throws CodeException
437ee5c0205SAndreas Gohr     * @throws SMTPException
438ee5c0205SAndreas Gohr     */
439ee5c0205SAndreas Gohr    protected function quit()
440ee5c0205SAndreas Gohr    {
441ee5c0205SAndreas Gohr        $in = "QUIT" . $this->CRLF;
442ee5c0205SAndreas Gohr        $code = $this->pushStack($in);
443ee5c0205SAndreas Gohr        if ($code !== '221'){
444ee5c0205SAndreas Gohr            throw new CodeException('221', $code, array_pop($this->resultStack));
445ee5c0205SAndreas Gohr        }
446ee5c0205SAndreas Gohr        return $this;
447ee5c0205SAndreas Gohr    }
448ee5c0205SAndreas Gohr
449ee5c0205SAndreas Gohr    protected function pushStack($string)
450ee5c0205SAndreas Gohr    {
451ee5c0205SAndreas Gohr        $this->commandStack[] = $string;
452ee5c0205SAndreas Gohr        fputs($this->smtp, $string, strlen($string));
453ee5c0205SAndreas Gohr        $this->logger && $this->logger->debug('Sent: '. $string);
454ee5c0205SAndreas Gohr        return $this->getCode();
455ee5c0205SAndreas Gohr    }
456ee5c0205SAndreas Gohr
457ee5c0205SAndreas Gohr    /**
458ee5c0205SAndreas Gohr     * get smtp response code
459ee5c0205SAndreas Gohr     * once time has three digital and a space
460ee5c0205SAndreas Gohr     * @return string
461ee5c0205SAndreas Gohr     * @throws SMTPException
462ee5c0205SAndreas Gohr     */
463ee5c0205SAndreas Gohr    protected function getCode()
464ee5c0205SAndreas Gohr    {
465ee5c0205SAndreas Gohr        while ($str = fgets($this->smtp, 515)) {
466ee5c0205SAndreas Gohr            $this->logger && $this->logger->debug("Got: ". $str);
467ee5c0205SAndreas Gohr            $this->resultStack[] = $str;
468ee5c0205SAndreas Gohr            if(substr($str,3,1) == " ") {
469ee5c0205SAndreas Gohr                $code = substr($str,0,3);
470ee5c0205SAndreas Gohr                return $code;
471ee5c0205SAndreas Gohr            }
472ee5c0205SAndreas Gohr        }
473ee5c0205SAndreas Gohr        throw new SMTPException("SMTP Server did not respond with anything I recognized");
474ee5c0205SAndreas Gohr    }
475ee5c0205SAndreas Gohr
476ee5c0205SAndreas Gohr}
477ee5c0205SAndreas Gohr
478