Copyright © 2012 Dirk-Jan C. Binnema

     Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A copy of the license is included in the section entitled ``GNU Free Documentation License.''

mu4e Manual
***********

Welcome to mu-guile!

mu-guile is a binding of the mu email search engine and the guile programming language.

Introduction
************

mu4e is an e-mail program for GNU/Emacs; it uses the mu maildir search engine as its backend, making mu fully search-based. mu is a program for indexing / searching e-mails, as well as an emacs-based email-client (mu4e.

guile is the GNU Ubiquitous Intelligent Language for Extensions - a version of the Scheme programming language and the official GNU extension language.

mu-guile connects mu and guile, and allows you to easily write programs to do things with your e-mails.

Getting started
***************

This chapter walks you through the installation and some basic steps to ensure things work correctly.

Installation
============

mu-guile is part of mu - by installing the latter, the former will be installed as well. Note, however, that mu-guile requires you to have guile version 2.0 installed, otherwise mu-guile will not be built/installed.

At the time of writing, there are no distribution packages for mu-guile yet, so we are assuming installation from source packages.

Installation follows the normal sequence of:

     $ tar xvfz mu-<version>.tar.gz  # use the specific version
     $ cd mu-<version>
     $./configure

The output of ./configure should end with a little text describing the detected versions of various libraries mu depends on. In particular, it should mention the guile version, e.g.

     Guile version                        : 2.0.3.82-a2c66

If you don't see any line referring to guile, please install it, and run configure again. Note once more, mu-guile requires guile version 2.0.

After a succesfull ./configure, we can make and install the package:

     $ make && sudo make install

After this, mu and mu-guile should be installed. Note that the above instructions will normally install things under /usr/local; you may need to update guile's %load-path to find it there.

You can check the current load-path with the following:

     guile -c '(display %load-path)(newline)'

If necessary, you can add the %load-path by adding something like the following to your ~/.guile:

     (set! %load-path (cons "/usr/local/share/guile/site/2.0" %load-path))

After this, you should be ready to go.

First steps
===========

Assuming mu-guile has been installed correctly (Installation), and also assuming that you have already indexed your e-mail messages (if necessary, see the mu-index man-page), we are ready to start mu-guile; a session may look something like this:

$ guile
GNU Guile 2.0.3.82-a2c66
Copyright (C) 1995-2011 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)>

Now, we need to load the mu-guile module:

scheme@(guile-user)> (use-modules (mu) (mu message))

This will load the basic modules for dealing with messages. After we have loaded the modules, we need to initialize the mu-guile system:

scheme@(guile-user)> (mu:initialize)

When this is done, we can start querying the database. We'll go into various functions later in this manual, but just to give an example, let's get a list of the subjects of all messages that mention hello:

scheme@(guile-user)> (for-each
                        (lambda(msg)
                          (format #t "Subject: ~a\n" (subject msg)))
                        (mu:message-list "hello"))

Initializing mu-guile
*********************

It is of course possible to write separate programs with mu-guile, but for now we'll do things interactively, i.e., from the Guile-prompt (``REPL'').

We start our mu-guile session by starting guile:

$ guile
GNU Guile 2.0.3.82-a2c66
Copyright (C) 1995-2011 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)>

Now, the first thing we need to do is load the mu-guile modules; currently, there are three available:

  * mu - initialization, functions to get messages, contacts

  * mu message - functions to deal with messages

  * mu contact - functions to deal with contacts

Let's simply load all of them:

scheme@(guile-user)> (use-modules (mu) (mu message) (mu contact))

Assuming you have installed everything correctly, the first time you do this, guile will probably respond by showing some message about compiling the modules, and then end with another prompt.

Before we can do anything with mu guile, we need to initialize the system. The reason as to not do this automatically is to enable people to use non-default places to keep there mu data files.

We can initialize the system with:

scheme@(guile-user)> (mu:initialize)

Which will use the default location of ~/.mu. Or, instead, if you keep your mu data in a non-standard place:

scheme@(guile-user)> (mu:initialize "/path/to/my/mu/")

If all worked up until here, we're ready to go with mu-guile.

Messages
********

In this chapter, we discuss how to find messages, and then how to do various things with them.

Finding messages
================

Now we are ready to retrieve some messages from the system. There are two principle functions to do this:

  * (mu:message-list [<search-expression>])

  * (mu:for-each-message <function> [<search-expression>])

The first function, mu:message-list returns a list of all messages matching <search-expression>; if you leave <search-expression> out, it returns all messages.

For example, to get all messages with coffee in the subject line, you could do:

scheme@(guile-user)> (mu:message-list "subject:coffee")
$1 = (#<<mu-message> 9040640> #<<mu-message> 9040630>
      #<<mu-message> 9040570>)

So, we get a list with three <mu-message> objects. We'll discuss them in a bit more detail in the next section, but let's just use the subject function ('method') provided by <mu-message> objects to retrieve the subject-field.

For your convenience, guile has saved the result in $1, so to get the subject of the first message in the list, we can do:

scheme@(guile-user)> (subject (car $1))
$2 = "Re: best coffee ever!"

The second function we mentioned, mu:for-each-message, executes some function for each message matched by the search expression (or all message if the search expression is omitted).

scheme@(guile-user)> (mu:for-each-message
                       (lambda(msg)
                         (display (subject msg))
                         (newline))
                      "subject:coffee")
Re: best coffee ever!
best coffee ever!
Coffee beans
scheme@(guile-user)>

Using mu:message-list and/or mu:for-each-message (Implementation node: mu:message-list is implemented in terms of mu:for-each-message, not the other way around. Due to the way mu works, mu:for-each-message is rather more efficient than a combination for for-each and mu:message-list) and a couple of <mu-message> methods, together with that Guile/Scheme provides should allow for many interesting programs.

Message functions
=================

Now that we've seen how to retrieve lists of message objects (<mu-message>), let's see what we can do with such an object.

<mu-message> defines the following methods (A note on naming: functions we have seen before -- mu:initialize, mu:message-list and mu:for-each-message are prefixed with mu:. This is not the case for the <mu-message> methods to be discussed next, such as the methods subject and from. Reason for this is that it is not needed, since these methods only recognized for <mu-message> objects, and do not affect anything else, while the mu:-prefixed are 'globally visible' and thus we need to be careful about naming conflicts) that all only take a single <mu-message> object as a parameter. We won't go into the exact meanings for all of these functions here - for the details about various flags / properties, please refer to the mu-find man-page.

  * bcc: the Bcc field of the message, or #f if there is none

  * body-html: : the html body of the message, or #f if there is none

  * body-txt: the plain-text body of the message, or #f if there is none

  * cc: the Bcc field of the message, or #f if there is none

  * date: the Date field of the message, or 0 if there is none

  * flags: list of message-flags for this message

  * from: the From field of the message, or #f if there is none

  * maildir: the maildir this message lives in, or #f if there is none

  * message-id: the Message-Id field of the message, or #f if there is none

  * path: the file system path for this message

  * priority: the priority of this message (either mu:low, mu:normal or mu:high

  * references: the list of messages (message-ids) this message refers to in the References: header

  * size: size of the message in bytes

  * subject: the Subject field of the message, or #f if there is none.

  * tags: list of tags for this message

  * to: the sender of the message, or #f if there is none.

With these functions, we can query messages for their properties; for example:

scheme@(guile-user)> (define msg (car (mu:message-list "snow")))
scheme@(guile-user)> (subject msg)
$1 = "Re: Running in the snow is beautiful"
scheme@(guile-user)> (flags msg)
$2 = (mu:replied mu:seen)
scheme@(guile-user)> (strftime "%F" (localtime (date msg)))
$3 = "2011-01-15"

There are a couple more functions:

  * (header <mu-message> "<header-name>") returns an arbitrary message header (or #f if not found) -- e.g. (header msg "User-Agent")

  * (contacts <mu-message> contact-type) which returns a list of contacts (names/e-mail addresses in the To/From/Cc/Bcc-fields). See Contacts.

Example - the longest subject
=============================

Now, let's write a little example -- let's find out what is the longest subject of any e-mail messages we received in the year 2011.  If you put the following in a separate file, make it executable, and run it like any program.

#!/bin/sh
exec guile -s $0 $@
!#

(use-modules (mu) (mu message))
(use-modules (srfi srfi-1))

(mu:initialize)

;; note: (subject msg) => #f if there is no subject
(define list-of-subjects
  (map (lambda (msg)
      (or (subject msg) "")) (mu:message-list "date:2011..2011")))
;; see the mu-find manpage for the date syntax

(define longest-subject
  (fold (lambda (subj1 subj2)
      (if (> (string-length subj1) (string-length subj2))
	subj1 subj2))
    "" list-of-subjects))

(format #t "Longest subject: ~s" longest-subject)
(newline)

There are many other ways to solve the same problem, for example by using an iterative approach with mu:for-each-message, but it should show how one can easily write little programs to answer specific questions about an e-mail corpus.

Contacts
********

We can retrieve the sender and recipients of an e-mail message using methods like from, to, cc and bcc; see Message functions. These functions return the list of recipients as a single string; however, often it is more useful to deal with recipients as separate objects.

mu-guile offers some functionality for this in the (mu contact) module.

Contact functions and objects
=============================

(use-modules (mu contact))

After loading the (mu contact), message objects (see Messages) gain the the contacts-methods:

(contacts <message-object> [<contact-type>])

The <contact-type> is a symbol, one of mu:to, mu:from, mu:cc or mu:bcc; this will then get the contact objects for the contacts of the corresponding type. If you leave out the contact-type (or specify #t for it, you will get a list of all contact objects for the message.

A contact object (<mu-contact>) has two methods:

  * name returns the name of the contact, or #f if there is none

  * email returns the e-mail address of the contact, or #f if there is none

Let's get a list of all names and e-mail addresses in the 'To:' field, of messages matching 'book':

(use-modules (mu) (mu message) (mu contact))
(mu:initialize)
(mu:for-each-message
   (lambda (msg)
      (for-each
        (lambda (contact)
           (format #t "~a => ~a\n"
             (or (email contact) "") (or (name contact) "no-name")))
        (contacts msg mu:to)))
    "book")

This shows what the methods do, but for many uses, it would be more useful to have each of the contacts only show up once - for that, please refer to see All contacts.

All contacts
============

Sometimes it may also be useful to look at all the different contacts in the mu database -- that is, all the different contacts. This is useful, for example, when exporting contacts to some external format that can then be important in an e-mail program.

To enable this, there is the function mu:for-each-contact, defined as

(mu:for-each-contact <function> [<search-expression>]).

This will aggregate the unique contacts from all messages matching <search-expression> (when it is left empty, it will match all messages in the database), and execute <function> for each of these contacts.

The <function> receives an object of the type <contact-with-stats>, which is a subclass of the <contact> class discussed in see Contact functions and objects. <contact-with-stats> objects expose the following methods:

  * frequency: returns the number of times this contact occured in one of the address fields

  * last-seen: returns the most recent time the contact was seen in one of the address fields, as a time_t value

The function aggregates per e-mail address; if a certain e-mail address occurs with different names, it uses the most recent non-empty name.

Example - mutt export
=====================

Let's see how we could export the addresses in the mu database to the addressbook format of the venerable mutt (http://www.mutt.org/) e-mail client.

The addressbook format that mutt uses is a sequence of lines that look something like:
alias <nick> [<name>] "<" <email> ">"

Many of the names in our database could be random people writing things in mailing lists, so we may want to limit it to people we have seen at least 10 times in the last year.

It is a bit hard to guess the nick name for e-mail contacts, so we are going to assume it is the lowercase version of the first word in <name>. You can always adjust them later by hand, obviously.

(use-modules (mu) (mu message) (mu contact))
(mu:initialize)

(mu:for-each-contact
   (lambda (contact)

GNU Free Documentation License
******************************

     [file fdl.texi not included]