I created a patch do get the GMAIL_AT cookie and the page content with the e-mails for the domain accounts. However, this is a dead end, since the format of the page content is different, and needs to be parsed differently.
It seems that it is much better to use IMAP to interact with Google Mail. One of the libgmail maintainers seems to be working on the new library called gmailimap, which even provides the same API as libgmail (though you don't need this if you were not using libgmail heavily in the first place). The project is here: http://gmailimap.wikidot.com
It includes a link to the SourceForge project page. Also, here is a relevant discussion on the subject: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=469331
This library works just as well for the domain accounts. You just need to specify the full e-mail, and keep the same servers and ports ('imap_server' : 'imap.gmail.com', 'imap_port' : 993, 'smtp_server' : 'smtp.gmail.com', 'smtp_port' : 587). Yes, gmail.com servers work for the Google Apps For Your Domain accounts. In either case, the users might need to enable IMAP in their account settings.
Below is the patch for getting the GMAIL_AT cookie and the page content for the domain accounts, in case someone will decide to try to parse it:
--- trunk/bigboard/stocks/mail/libgmail_patched.py (original)
+++ trunk/bigboard/stocks/mail/libgmail_patched.py Wed May 7 19:51:55 2008
@@ -84,6 +84,10 @@
the embedded Javascript.
"""
+ if LG_DEBUG:
+ # This will print the page content we are about to parse to get the e-mails.
+ # The current parsing does not work for what is returned for Google Apps For Your Domain accounts.
+ print "pageContent %s" % pageContent
lines = pageContent.splitlines()
data = '\n'.join([x for x in lines if x and x[0] in ['D', ')', ',', ']']])
#data = data.replace(',,',',').replace(',,',',')
@@ -141,8 +145,9 @@
return result
def http_error_302(self, req, fp, code, msg, headers):
# The location redirect doesn't seem to change
@@ -152,6 +157,8 @@
headers.getheader('Location'))
if new_host:
req.add_header("Host", new_host.groups()[0])
+ if self.extractCookies:
+ self.cookiejar.extractCookies(headers)
result = urllib2.HTTPRedirectHandler.http_error_302(
self, req, fp, code, msg, headers)
return result
@@ -179,10 +186,15 @@
# TODO: Do this all more nicely?
for cookie in headers.getheaders('Set-Cookie'):
name, value = (cookie.split("=", 1) + [""])[:2]
- if LG_DEBUG: print "Extracted cookie `%s`" % (name)
+ if LG_DEBUG:
+ print "Extracted cookie `%s`" % (name)
if not nameFilter or name in nameFilter:
- self._cookies[name] = value.split(";")[0]
- if LG_DEBUG: print "Stored cookie `%s` value `%s`" % (name, self._cookies[name])
+ cookie_value = value.split(";")[0]
+ # do not overwrite the HID cookie when we get information that it is expired
+ if not (name == "HID" and cookie_value == "EXPIRED"):
+ self._cookies[name] = cookie_value
+ if LG_DEBUG:
+ print "Stored cookie `%s` value `%s`" % (name, self._cookies[name])
if self._cookies[name] == "EXPIRED":
if LG_DEBUG:
print "We got an expired cookie: %s:%s, deleting." % (name, self._cookies[name])
@@ -289,7 +301,7 @@
"""
self.domain = domain
if self.domain:
- URL_LOGIN = "https://www.google.com/a/" + self.domain + "/LoginAction"
+ URL_LOGIN = "https://www.google.com/a/" + self.domain + "/LoginAction2"
URL_GMAIL = "http://mail.google.com/a/" + self.domain + "/?"
else:
URL_LOGIN = GMAIL_URL_LOGIN
@@ -306,10 +318,13 @@
gmail_transport.ConnectHTTPSHandler(proxy = PROXY_URL),
SmartRedirectHandler(self._cookieJar))
else:
+ # processing of the Google Apps For Your Domain login requires extracting cookies
+ # before redirects, so we pass self.domain for the extractCookies flag to the
+ # SmartRedirectHandler
self.opener = urllib2.build_opener(
urllib2.HTTPHandler(debuglevel=0),
urllib2.HTTPSHandler(debuglevel=0),
- SmartRedirectHandler(self._cookieJar))
+ SmartRedirectHandler(self._cookieJar, self.domain))
elif state:
# TODO: Check for stale state cookies?
self.name, self._cookieJar = state.state
@@ -331,8 +346,8 @@
data = urllib.urlencode({'continue': URL_GMAIL,
'at' : 'null',
'service' : 'mail',
- 'userName': self.name,
- 'password': self.password,
+ 'Email': self.name,
+ 'Passwd': self.password,
})
else:
data = urllib.urlencode({'continue': URL_GMAIL,
@@ -363,6 +378,14 @@
# We aren't concerned with the actual content of this page,
# just the cookie that is returned with it.
pageData = self._retrievePage(redirectURL)
+ else:
+ if LG_DEBUG:
+ print "cookie jar has HID cookie: %s" % (self._cookieJar._cookies.has_key('HID'))
+ if self._cookieJar._cookies.has_key('HID'):
+ req2 = urllib2.Request("https://mail.google.com/a/" + self.domain + "/?auth=" + self._cookieJar._cookies['HID'] + "husr=" + self.name + "@" + self.domain)
+ pageData2 = self._retrievePage(req2)
+ else:
+ raise GmailLoginFailure("Login failed. (Wrong username/password?)")
def _retrievePage(self, urlOrRequest):
"""
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi, I'm having trouble using domain="mydomain.com" with gmail.
I'm not getting the cookies that libgmail needs, especially GMAIL_AT
Running a simple example with LG_DEBUG=1 gives me:
>pythonw -u "SslMailClient.py"
Extracted cookie `GALX`
Stored cookie `GALX` value `DOLmiVjJA8g`
No messages found
Traceback (most recent call last):
File "SslMailClient.py", line 57, in <module>
genericEmail("myusername@gmail.com", "Testing Apps", "If you're reading this, it's working")
File "SslMailClient.py", line 50, in genericEmail
ga.sendMessage(gmsg)
File "C:\jimc\anl\PLUS\CyberBully\WebSite\cgi-bin\libgmail_anl.py", line 588, in sendMessage
U_ACTION_TOKEN: self._getActionToken(),
File "C:\jimc\anl\PLUS\CyberBully\WebSite\cgi-bin\libgmail_anl.py", line 563, in _getActionToken
at = self._cookieJar._cookies[ACTION_TOKEN_COOKIE]
KeyError: 'GMAIL_AT'
>Exit code: 1
I mirrored the ?ui=1 fix in the GmailAccount _init_ like so:
if self.domain:
URL_LOGIN = "https://www.google.com/a/" + self.domain + "/LoginAction"
URL_GMAIL = "https://mail.google.com/a/" + self.domain + "/?ui=1"
But no luck...
I created a patch do get the GMAIL_AT cookie and the page content with the e-mails for the domain accounts. However, this is a dead end, since the format of the page content is different, and needs to be parsed differently.
It seems that it is much better to use IMAP to interact with Google Mail. One of the libgmail maintainers seems to be working on the new library called gmailimap, which even provides the same API as libgmail (though you don't need this if you were not using libgmail heavily in the first place). The project is here:
http://gmailimap.wikidot.com
It includes a link to the SourceForge project page. Also, here is a relevant discussion on the subject:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=469331
This library works just as well for the domain accounts. You just need to specify the full e-mail, and keep the same servers and ports ('imap_server' : 'imap.gmail.com', 'imap_port' : 993, 'smtp_server' : 'smtp.gmail.com', 'smtp_port' : 587). Yes, gmail.com servers work for the Google Apps For Your Domain accounts. In either case, the users might need to enable IMAP in their account settings.
Feel free to take a look at
http://svn.gnome.org/viewvc/bigboard/trunk/bigboard/gmailimap/
for our local modifications of the gmailimap and for how we use it in the Mail widget for the GNOME Online Desktop:
http://svn.gnome.org/viewvc/bigboard/trunk/bigboard/stocks/mail/MailStock.py
Hope this helps.
Marina
Below is the patch for getting the GMAIL_AT cookie and the page content for the domain accounts, in case someone will decide to try to parse it:
--- trunk/bigboard/stocks/mail/libgmail_patched.py (original)
+++ trunk/bigboard/stocks/mail/libgmail_patched.py Wed May 7 19:51:55 2008
@@ -84,6 +84,10 @@
the embedded Javascript.
"""
+ if LG_DEBUG:
+ # This will print the page content we are about to parse to get the e-mails.
+ # The current parsing does not work for what is returned for Google Apps For Your Domain accounts.
+ print "pageContent %s" % pageContent
lines = pageContent.splitlines()
data = '\n'.join([x for x in lines if x and x[0] in ['D', ')', ',', ']']])
#data = data.replace(',,',',').replace(',,',',')
@@ -141,8 +145,9 @@
return result
class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
- def __init__(self, cookiejar):
+ def __init__(self, cookiejar, extractCookies = False):
self.cookiejar = cookiejar
+ self.extractCookies = extractCookies
def http_error_302(self, req, fp, code, msg, headers):
# The location redirect doesn't seem to change
@@ -152,6 +157,8 @@
headers.getheader('Location'))
if new_host:
req.add_header("Host", new_host.groups()[0])
+ if self.extractCookies:
+ self.cookiejar.extractCookies(headers)
result = urllib2.HTTPRedirectHandler.http_error_302(
self, req, fp, code, msg, headers)
return result
@@ -179,10 +186,15 @@
# TODO: Do this all more nicely?
for cookie in headers.getheaders('Set-Cookie'):
name, value = (cookie.split("=", 1) + [""])[:2]
- if LG_DEBUG: print "Extracted cookie `%s`" % (name)
+ if LG_DEBUG:
+ print "Extracted cookie `%s`" % (name)
if not nameFilter or name in nameFilter:
- self._cookies[name] = value.split(";")[0]
- if LG_DEBUG: print "Stored cookie `%s` value `%s`" % (name, self._cookies[name])
+ cookie_value = value.split(";")[0]
+ # do not overwrite the HID cookie when we get information that it is expired
+ if not (name == "HID" and cookie_value == "EXPIRED"):
+ self._cookies[name] = cookie_value
+ if LG_DEBUG:
+ print "Stored cookie `%s` value `%s`" % (name, self._cookies[name])
if self._cookies[name] == "EXPIRED":
if LG_DEBUG:
print "We got an expired cookie: %s:%s, deleting." % (name, self._cookies[name])
@@ -289,7 +301,7 @@
"""
self.domain = domain
if self.domain:
- URL_LOGIN = "https://www.google.com/a/" + self.domain + "/LoginAction"
+ URL_LOGIN = "https://www.google.com/a/" + self.domain + "/LoginAction2"
URL_GMAIL = "http://mail.google.com/a/" + self.domain + "/?"
else:
URL_LOGIN = GMAIL_URL_LOGIN
@@ -306,10 +318,13 @@
gmail_transport.ConnectHTTPSHandler(proxy = PROXY_URL),
SmartRedirectHandler(self._cookieJar))
else:
+ # processing of the Google Apps For Your Domain login requires extracting cookies
+ # before redirects, so we pass self.domain for the extractCookies flag to the
+ # SmartRedirectHandler
self.opener = urllib2.build_opener(
urllib2.HTTPHandler(debuglevel=0),
urllib2.HTTPSHandler(debuglevel=0),
- SmartRedirectHandler(self._cookieJar))
+ SmartRedirectHandler(self._cookieJar, self.domain))
elif state:
# TODO: Check for stale state cookies?
self.name, self._cookieJar = state.state
@@ -331,8 +346,8 @@
data = urllib.urlencode({'continue': URL_GMAIL,
'at' : 'null',
'service' : 'mail',
- 'userName': self.name,
- 'password': self.password,
+ 'Email': self.name,
+ 'Passwd': self.password,
})
else:
data = urllib.urlencode({'continue': URL_GMAIL,
@@ -363,6 +378,14 @@
# We aren't concerned with the actual content of this page,
# just the cookie that is returned with it.
pageData = self._retrievePage(redirectURL)
+ else:
+ if LG_DEBUG:
+ print "cookie jar has HID cookie: %s" % (self._cookieJar._cookies.has_key('HID'))
+ if self._cookieJar._cookies.has_key('HID'):
+ req2 = urllib2.Request("https://mail.google.com/a/" + self.domain + "/?auth=" + self._cookieJar._cookies['HID'] + "husr=" + self.name + "@" + self.domain)
+ pageData2 = self._retrievePage(req2)
+ else:
+ raise GmailLoginFailure("Login failed. (Wrong username/password?)")
def _retrievePage(self, urlOrRequest):
"""
Here is the version of the patch with preserved indentation:
http://svn.gnome.org/viewvc/bigboard/trunk/bigboard/stocks/mail/libgmail_patched.py?r1=7278&r2=7334&diff_format=u
or
http://sourceforge.net/tracker/index.php?func=detail&aid=1937377&group_id=113492&atid=665330
Marina
The latest libgmail (from CVS) works for Google Apps For Your Domain accounts. It was resolved in
http://sourceforge.net/tracker/index.php?func=detail&aid=1937377&group_id=113492&atid=665330