ILeo example: getting gmail to leo

14 views
Skip to first unread message

Ville M. Vainio

unread,
Sep 6, 2008, 7:50:22 AM9/6/08
to leo-e...@googlegroups.com
Here's an example ileo snippet to get your gmail threads with "todo"
label into leo outline (under heading MyTodo):

QQQ
import ipy_gmail

gml todo
ipy_gmail.to_leo(_, wb.MyTodo)
QQQ

Just posting this as an example of an interesting "productivity
feature" to emphasize how ileo reduces the amount of typing and
thinking that needs to be done. "gml" is a magic function introduced
in ipy_gmail that searches gmails with the specified label. You still
need to find this node and press alt+I, but once we get @button
working with ileo we can forget about that as well ;-)

--
Ville M. Vainio - vivainio.googlepages.com
blog=360.yahoo.com/villevainio - g[mail | talk]='vivainio'

Edward K. Ream

unread,
Sep 7, 2008, 5:23:40 PM9/7/08
to leo-editor


On Sep 6, 6:50 am, "Ville M. Vainio" <vivai...@gmail.com> wrote:
> Here's an example ileo snippet to get your gmail threads with "todo"
> label into leo outline (under heading MyTodo):

Thanks for this. I've put it on the list of things to document.

Edward

Ville M. Vainio

unread,
May 7, 2009, 3:33:33 PM5/7/09
to bpursley, leo-e...@googlegroups.com
On Thu, May 7, 2009 at 10:09 PM, bpursley <ber...@bpursley.net> wrote:

> Has there been any more written about using Leo for gmail?  Are there
> any plugins available?

Not really - but such a plugin would be very easy to write using libgmail:

http://libgmail.sourceforge.net/

What would perhaps be more interesting is imap plugin. Many people use
gmail for personal stuff, but imap is more widely available in
corporate setting (because Outlook supports imap) where archiving big
amounts of emails is a better use case.

E.g. Chandler ( http://chandlerproject.org/ ) operates by having a
dedicated folder on an imap server; similar setup could be handy for
leo as well.

--
Ville M. Vainio
http://tinyurl.com/vainio

Ville M. Vainio

unread,
May 7, 2009, 3:49:50 PM5/7/09
to bpursley, leo-e...@googlegroups.com
On Thu, May 7, 2009 at 10:33 PM, Ville M. Vainio <viva...@gmail.com> wrote:

> What would perhaps be more interesting is imap plugin. Many people use
> gmail for personal stuff, but imap is more widely available in
> corporate setting (because Outlook supports imap) where archiving big
> amounts of emails is a better use case.

And it seems gmail works just fine python imaplib. So who's the first
to create the leo email client?

Try out this program (if you have enabled imap on our gmail account):

QQQ

import getpass, imaplib

M = imaplib.IMAP4_SSL('imap.gmail.com', 993)
M.login(raw_input('username:') + '@gmail.com', getpass.getpass())
M.select()
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, '(RFC822)')
print 'Message %s\n%s\n' % (num, data[0][1])
M.close()
M.logout()

QQQ

Edward K. Ream

unread,
May 9, 2009, 8:36:53 AM5/9/09
to leo-e...@googlegroups.com
On Thu, May 7, 2009 at 2:49 PM, Ville M. Vainio <viva...@gmail.com> wrote:


Try out this program (if you have enabled imap on our gmail account):

Cool!  It works as a stand-alone python app, but if I try to execute it as a Leo script I get this, endlessly repeated:

QCoreApplication::exec: The event loop is already running


Edward

Ville M. Vainio

unread,
May 9, 2009, 9:02:40 AM5/9/09
to leo-e...@googlegroups.com
On Sat, May 9, 2009 at 2:36 PM, Edward K. Ream <edre...@gmail.com> wrote:

> Cool!  It works as a stand-alone python app, but if I try to execute it as a
> Leo script I get this, endlessly repeated:
>
> QCoreApplication::exec: The event loop is already running

Ah, it's the raw_input.

Try removing it:

username = 'someusername'
passwd = 'foobar'
M.login(username + '@gmail.com', passwd)

Edward K. Ream

unread,
May 9, 2009, 2:04:25 PM5/9/09
to leo-e...@googlegroups.com
On Sat, May 9, 2009 at 8:02 AM, Ville M. Vainio <viva...@gmail.com> wrote:

On Sat, May 9, 2009 at 2:36 PM, Edward K. Ream <edre...@gmail.com> wrote:

> Cool!  It works as a stand-alone python app, but if I try to execute it as a
> Leo script I get this, endlessly repeated:
>
> QCoreApplication::exec: The event loop is already running

Ah, it's the raw_input.

Try removing it:

Yes.  That worked.  Thanks.

Edward

Edward K. Ream

unread,
May 9, 2009, 2:36:42 PM5/9/09
to leo-e...@googlegroups.com
On Thu, May 7, 2009 at 2:49 PM, Ville M. Vainio <viva...@gmail.com> wrote:

Try out this program (if you have enabled imap on our gmail account):

Here are a few tweaks.  Replace the username.

QQQ

import getpass, imaplib

username = 'edre...@gmail.com' # change as needed.


M = imaplib.IMAP4_SSL('imap.gmail.com', 993)
M.login(username, getpass.getpass())

M.select()
typ, data = M.search(None, 'ALL')
for num in data[0].split():
    typ, data = M.fetch(num, '(RFC822)')
    s = data[0][1]
    s = s.replace('\r','')
    i = s.find('\n\n')
    if i == -1:
        head = '' ; tail = s
    else:
        head,tail = s[:i+2],s[i+2:].lstrip()
    print 'Message %3s %s' % (num,len(tail))
    p2 = p.insertAsLastChild()
    p2.setHeadString('mail %s' % num)
    p2.setBodyString(tail)
    if head:
        p3 = p2.insertAsLastChild()
        p3.setHeadString('head %s' % num)
        p3.setBodyString(head)
print 'done'
M.close()
M.logout()
c.redraw()

QQQ

The new code creates nodes for each message, and puts the header in a child.  This code finds the end of the header by searching for two consecutive newlines.  Presumably there is an official way to do this, but it doesn't jump out at me.

Another improvement would be to label each node with the sender and time, instead of the message number.  Even as it is, though, the code is useful.

BTW, I suspect Leo must be running from a console so the call to M.login will have a place to get input.

Edward

Edward K. Ream

unread,
May 9, 2009, 2:54:34 PM5/9/09
to leo-e...@googlegroups.com
On Sat, May 9, 2009 at 1:36 PM, Edward K. Ream <edre...@gmail.com> wrote:

Here are a few tweaks [snip]

I put my password in ~/gmail.pass and replaced everything before the call to M.select() with::

QQQ
import getpass,imaplib,os

username = 'edre...@gmail.com'
passfile = os.path.expanduser('~/gmailpass.txt')
M = imaplib.IMAP4_SSL('imap.gmail.com',993)
try:
    f = open(passfile)
    password = f.read()
    M.login(username,password)
except IOError:
    M.login(username, getpass.getpass())
QQQ

Now I don't have to type my password each time.  Of course, my gmail password is insecure, but I don't care...

EKR

Ville M. Vainio

unread,
May 9, 2009, 5:07:03 PM5/9/09
to leo-e...@googlegroups.com
On Sat, May 9, 2009 at 8:36 PM, Edward K. Ream <edre...@gmail.com> wrote:

> The new code creates nodes for each message, and puts the header in a
> child.  This code finds the end of the header by searching for two
> consecutive newlines.  Presumably there is an official way to do this, but
> it doesn't jump out at me.

The official way is doing proper mime parsing; that way you can save
attachments as well.

Module 'email' does this quite easily:
http://docs.python.org/library/email.parser.html

email.message_from_string() does the parsing, and after that you just
deal with the mime parts. In my libgmail hack, I took the body
something like this:

http://pastebin.com/f4e80d3ba

Edward K. Ream

unread,
May 9, 2009, 7:58:48 PM5/9/09
to leo-e...@googlegroups.com
On Sat, May 9, 2009 at 4:07 PM, Ville M. Vainio <viva...@gmail.com> wrote:

The official way is doing proper mime parsing; that way you can save
attachments as well.

Module 'email' does this quite easily:
http://docs.python.org/library/email.parser.html

Thanks for this hint.  Here is the latest version of my script, on the trunk in test.leo at rev 1791.

import email,getpass,imaplib,os


username = 'edre...@gmail.com'
passfile = os.path.expanduser('~/gmailpass.txt')
M = imaplib.IMAP4_SSL('imap.gmail.com',993)
try:
    f = open(passfile)
    password = f.read()
    M.login(username,password)
except IOError:
    g.es_print('file not found: %s' % (passfile),color='red')
    # M.login(username, getpass.getpass())


M.select()
typ, data = M.search(None, 'ALL')
for num in data[0].split():
    typ, data = M.fetch(num,'(RFC822)')
    s = data[0][1]
    m = email.message_from_string(s)
    # for z in m.keys(): print z
    payload = m.get_payload()
    p2 = p.insertAsLastChild()
    date,from_s,subject = m['date'],m['from'],m['subject']
    p2.setHeadString(subject)
    body = '@nocolor\n\n%s\n%s\n%s\n\n%s' % (
        date,from_s,subject,payload)
    p2.setBodyString(body)

print 'done'
M.close()
M.logout()
c.redraw()

Edward
Reply all
Reply to author
Forward
0 new messages