14
votes

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.

2
Because I'm new, Stack Overflow's spam filter made me take out the links to the Gmail OAuth announcement ( googlecode.blogspot.com/2010/03/… ) and sample code ( code.google.com/p/google-mail-xoauth-tools/wiki/PhpSampleCode ).Curtis Gibby
can you make a web application that sends email using through gmail via javascript alone. Like tell gmail servers to send it for the user.Muhammad Umer

2 Answers

4
votes

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.

2
votes

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'