Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Gmail OAuth API to send email (especially via SMTP)?

I'm developing a web application that will send emails on behalf of a logged-in user.

I'm trying to use the new Gmail OAuth protocol announced described here to send these emails through the user's Gmail account (preferably using SMTP rather than IMAP, but I'm easy). However, the sample PHP code gives me a couple of problems.

  1. All of the sample code is based on IMAP, not SMTP. Why "support" the SMTP protocol if you're not going to show people how to use it?
  2. The sample code gives me a fatal error from an uncaught Zend exception -- it can't find the "INBOX" folder.

Fatal error: Uncaught exception 'Zend_Mail_Storage_Exception' with message 'cannot change folder, maybe it does not exist' in path\to\xoauth-php-samples\Zend\Mail\Storage\Imap.php:467 Stack trace: #0 path\to\xoauth-php-samples\Zend\Mail\Storage\Imap.php(248): Zend_Mail_Storage_Imap->selectFolder('INBOX') #1 path\to\xoauth-php-samples\three-legged.php(184): Zend_Mail_Storage_Imap->__construct(Object(Zend_Mail_Protocol_Imap)) #2 {main} Next exception 'Zend_Mail_Storage_Exception' with message 'cannot select INBOX, is this a valid transport?' in path\to\xoauth-php-samples\Zend\Mail\Storage\Imap.php:254 Stack trace: #0 path\to\xoauth-php-samples\three-legged.php(184): Zend_Mail_Storage_Imap->__construct(Object(Zend_Mail_Protocol_Imap)) #1 {main} in path\to\xoauth-php-samples\Zend\Mail\Storage\Imap.php on line 254

I've verified that I'm getting good OAuth tokens back, I just don't know how to make the actual email transaction happen. This protocol is still rather new, so there's not much unofficial community documentation about it out there, and the official docs are unhelpfully dry stuff about the SMTP RFC. So if anyone can help get this going, I'd greatly appreciate it.

Note: I've already been able to connect to Gmail's SMTP server via SSL and successfully send an email, provided that the user has given my application his/her Gmail username and password. I'd like to avoid this method, because it encourages phishing and security-minded users won't accept it. This question is not about that.

like image 203
Curtis Gibby Avatar asked Apr 08 '10 19:04

Curtis Gibby


People also ask

Does Gmail API use SMTP?

Gmail API uses open authentication (Oauth2), which only lets you request the scope of access you need. SMTP provides full access to the account using client login and password SMTP authentication.


2 Answers

I'm using a Google Apps account and trying to create an application that allows my users to send mail through SMTP via the new Oauth authorization. I was able to get it to work using some of the information on this discussion. However, I think I should clarify a couple things that I stumbled over...

1) The Zend framework for SMTP apparently automatically looks in the Zend/Mail/Protocol/Smtp/Auth folder for a file name .php in this case "Xoauth.php" which does NOT normally exist in Zend unless you create it. I was able to do this successfully by copying the existing Login.php file to Xoauth.php and modifying it slightly with the suggestions made on this web page.

This was very helpful but it is only part of the Xoauth.php file (Edit a copy of login.php and you will see an equivalent area):

// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH XOAUTH ' . $this->_xoauth_request);
$this->_expect(235);
$this->_auth = true;

2) Note that you should definitely have Zend on the PHP include_path even if you reference it directly in PHP because it may try to reference itself with its Loader.php file without using an explicit path.

3) Besides removing the obvious IMAP functions and replacing them with the equivalent SMTP functions I did not need to change the code from the Google OAuth samples for PHP. I did have to include the Zend/Mail.php file in order to Send email and add the code necessary to actually send email for the test to work.

like image 124
user453306 Avatar answered Oct 06 '22 09:10

user453306


Are you using a Google Apps account?

When redirecting to to the OAuthAuthorize token URL, I was mistakenly specifying hd=default. This tells the OAuth endpoint to authorize a token for a standard Google account and it does NOT work with Google Apps.

So, in three-legged.php, replace the line that says:

$consumer->redirect(array('hd' => 'default'));

with

$consumer->redirect();

And everything should be fine-- you should be asked to select between your consumer and Google Apps account if logged in with both.

Hope this helps-- I'll be patching the code to fix this issue.

Cheers, -Ryan

#

Re using SMTP-- I haven't gotten this fully together yet in a way that's documented well-- but here's the basics.

1) Create Zend/Mail/Protocol/Smtp/Auth/Xoauth.php, where the auth() method is fairly simple:

// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH XOAUTH ' . $this->_xoauth_request);
$this->_expect(235);
$this->_auth = true;

2) Generate $initClientRequest slightly differently, as the URL changes for SMTP versus IMAP 3) Send mail like the following:

  // where getXoauthClientRequest abstracts out line 116-165 in existing three-legged.php
  $smtpInitClientRequestEncoded = getXoauthClientRequest($smtpUrl, $accessToken);

  $config = array('ssl' => 'ssl',
                  'port' => '465',
                  'auth' => 'xoauth',
                  'xoauth_request' => $smtpInitClientRequestEncoded);

  $transport = new Zend_Mail_Transport_Smtp('smtp.gmail.com', $config);
  $mail = new Zend_Mail();
  $mail->setBodyText('This is the text of the mail.');
  $mail->setFrom($email_address, 'Some Sender');
  $mail->addTo($email_address, 'Some Recipient');
  $mail->setSubject('TestSubject');
  $mail->send($transport);

I'll try to create something better documented-- which doesn't require creating classes in the Zend 'namespace', but it'd probably require extending Zend_Mail_Transport_Smtp too because of the way _sendMail() is written in there to load auth classes only from the Zend_Mail_Protocol_Smtp_Auth_* 'package'

like image 30
user325700 Avatar answered Oct 06 '22 08:10

user325700