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