Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/gongzhitaao/GnusSolution

A complete working solution of gnus+offlineimap+dovecot+msmtp+cron
https://github.com/gongzhitaao/GnusSolution

cron dovecot emacs-configuration gnus msmtp offlineimap

Last synced: 3 months ago
JSON representation

A complete working solution of gnus+offlineimap+dovecot+msmtp+cron

Awesome Lists containing this project

README

        

#+TITLE: Complete Gnus

*SWITCHED TO mu4e, THE CODE IS PROVIDED AS IT-IS, MAY NOT UPDATE IT ANYMORE.*

This repo demonstrate one *complete* and *working* solution to
reading/writing mails in Gnus, with the help of =offlineimap=,
=dovecot=, =msmtp= and =cron=. Concretely, this repo contains

1. necessary configuration files for each component,
2. a brief summary of the big picture and detailed explanation on how
the components work together, and
3. helpful resource links.

/Note: The conf is tested under Ubuntu, it should work fine for all
Linux distributions provided each component be properly installed./

* Dependencies
:PROPERTIES:
:CUSTOM_ID: sec:dependencies
:END:

1. gnus, http://www.gnus.org/
2. offlineimap, http://www.offlineimap.org/
3. dovecot, https://www.dovecot.org/
4. msmtp, http://msmtp.sourceforge.net/
5. cron, https://directory.fsf.org/wiki/Vixie-cron

* Requirements
:PROPERTIES:
:CUSTOM_ID: sec:requirements
:END:

1. Basic knowledge of Linux environment
2. Comfortable with command line.
3. Good knowledge of =emacs= and =gnus=.

* How to Use
:PROPERTIES:
:CUSTOM_ID: sec:how-to-use
:END:

Make sure all dependencies are installed properly and stop =dovecot=
service if it is running in background.

1. /Edit/ and copy =msmtprc=, =netrc= and =offlineimaprc= to
=~/.msmtprc=, =~/.netrc= and =~/.offineimaprc=. Note that ~.netrc~
need to be set to mode ~600~, otherwise ~msmtp~ may complain.
2. Edit =10-mail.conf= (detailed below).
3. Invoke =offlineimap= manually. Sit back and have a cup of coffee,
it will takes quite some time to download all the mails for the
first time. Once finished, you should be able to see a similar
folder structure.

#+BEGIN_EXAMPLE
~/Mail/
├── archive
├── cur
├── drafts
├── Gmail
│   ├── archive
│   │   ├── cur
│   │   ├── new
│   │   └── tmp
│   ├── flagged
│   │   ├── cur
│   │   ├── new
│   │   └── tmp
│   ├── important
│   │   ├── cur
│   │   ├── new
│   │   └── tmp
│   ├── inbox
│   │   ├── cur
│   │   ├── new
│   │   └── tmp
│   ├── sent
│   │   ├── cur
│   │   ├── new
│   │   └── tmp
│   └── trash
│   ├── cur
│   ├── new
│   └── tmp
├── new
└── tmp
#+END_EXAMPLE

4. Start =dovecot= by =sudo service dovecot start=.
5. Register the =cron= job by =crontab cron-jobs=.
5. Open =emacs= and fire up =gnus=. And that's it!

* The Big Picture
:PROPERTIES:
:CUSTOM_ID: sec:the-big-picture
:END:

This section gives a brief summary of what each component does, and
does not if necessary.

- offlineimap :: It does mainly two things:
1. retrive mail from server to local folder, and
2. sync flags on local mails to server. For example, when you
finish reading a mail in =gnus=, the mail is marked as /read/;
=offlineimap= will sync this /read/ flag to the server to make
sure that the mail on the server is also marked as /read/.

It does *NOT* do two things,
1. send mails, which is done by =msmtp=;
2. invoke itself, which is done by =cron=.

- msmtp :: It sends mails. It will be automatically invoked by
=gnus=. You never need to manually start the program yourself.
Actually most of the time you are not even aware of its
existence.

- dovecot :: It serves mails. =dovecot= is a simple yet powerful mail
server. Wait, why do we ever need a local server? =offlineimap=
already downloads all the mails to local folders, and =gnus=
/can/ directly read local folders, why bother with another mail
server? Because =gnus= sometimes messes up the IMAP mails.
=gnus= is known to have problems properly handling flags, e.g.,
/read/, on mails. Instead of using /gnus/ to directly messing up
with mail, we use a delicate mail server, =dovecot= to interact
with mails professionally. In this case, =gnus= only tells
=dovecot= what it wants to do and =dovecot= does it accordingly.
For example, when finishing reading a mail in =gnus=, =gnus=
notifies =dovecot= that this mail should be marked as /read/,
=dovecot= does it accordingly. And as you already know it, this
/read/ flag with be synced by =offlineimap=.

- cron :: Invoke `offlineimap` periodically. =offlineimap= does not
run by itself magically, we need to invoke =offlineimap=
periodically to sync between local and remote. You may also
invoke =offlineimap= manually if that's how want it LOL.

- gnus :: You read/write/reply/... mails in it. Basically it is a
interface where you interact with mails. Although =gnus= can
actually finished all aforementioned jobs by itself (woooof), I
decide to use professional utilities to handle what it is best
at.

- netrc :: The `netrc` file stores the password. It has to be set to
mode `600` (read/write by current login user only) to work
properly.

* Devil in the detail
:PROPERTIES:
:CUSTOM_ID: sec:devil-in-the-detail
:END:

This section explains in detail configuration of each component. Note
that there are many possible working configurations available, what's
outlined here is just one of them (as a result of my years of
frustration).

** offlineimap
:PROPERTIES:
:CUSTOM_ID: subsec:offlineimap
:END:

Full configuration in [[file:offlineimaprc]].

The configuration is minimum yet fully functional. Most of the
configuration are self-evident except for, perhaps, the =nametrans=.

According to the official [[http://www.offlineimap.org/doc/versions/v6.5.6/nametrans.html#nametrans][document on =nametrans=]], it allows you to
have different folder name other than the names on the remote server.
For example, when login in Gmail, you will see folders [fn:1], e.g.,
=Sent Mail= for sent mails, =Trash= for deleted mails, etc. Different
mail server may name these folders differently. If you want a unified
names locally, you can use =nametrans= features to map a remote folder
to the local folder with a different name, e.g., =sent= for sent mails
that syncs with =Sent Mail=, =trash= for deleted mails that syncs with
=Trash=, etc.

In my configuration, =nametrans= takes a Python function, with sole
parameter =folder=, i.e., the remote folder name in string.

=folderfilter= controls which folders to sync. Please refer to
[[http://www.offlineimap.org/doc/versions/v6.5.6/nametrans.html#folderfilter][document on =folderfilter=]] for more details.

** msmtp
:PROPERTIES:
:CUSTOM_ID: subsec:msmtp
:END:

Full configuration in [[file:msmtprc]].

The configuration is just standard. I copied the configuration from
online.

** dovecot
:PROPERTIES:
:CUSTOM_ID: subsec:dovecot
:END:

Full [fn:2] configuration in [[file:10-mail.conf]].

There is only one change made in =10-mail.conf= which usually resides
in =/etc/dovecot/conf.d/=.

** cron
:PROPERTIES:
:CUSTOM_ID: subsec:cron
:END:

The cron job to invoke =offlineimap= periodically is listed in
[[file:cron-jobs]].

Register this cron job, the =cron= will invoke =offlineimap=
periodically.

** gnus
:PROPERTIES:
:CUSTOM_ID: subsec:gnus
:END:

Full configuration in [[file:gnus-conf.el]].

This is the most /frustrating/ part. I copied my full configuration
here just for your information. However, the essential part that
makes it /just work/ are detailed as follows.

*** Connect to =dovecot=

#+BEGIN_SRC emacs-lisp
(setq gnus-select-method
'(nnimap "LocalMail"
(nnimap-address "localhost")
(nnimap-stream network)
(nnimap-server-port 143)))
#+END_SRC

Remember that we have a local mail server, =dovecot=, running? The
above code connects =gnus= to =dovecot=. Whenever we/gnus want to
read mails, =gnus= notifies =dovecot= which retrieves mails from local
folder and send it to =gnus=.

*** Read mails

#+BEGIN_SRC emacs-lisp
(setq mail-user-agent 'gnus-user-agent)
(setq read-mail-command 'gnus)
#+END_SRC

The above code notifies =emacs= that we want to use =gnus= to handle
mails, since there are other options, e.g., =rmail=.

*** Send mails

#+BEGIN_SRC emacs-lisp
(setq send-mail-function 'message-send-mail-with-sendmail)
(setq sendmail-program "msmtp")
#+END_SRC

The above code specifies that we want to use =msmtp= to send mails.
Basically when finish editing a mail in =gnus=, you hit C-c
C-c
, the =gnus= automatically invoke =msmtp= to send mails.

**** Where to store sent mails

#+BEGIN_SRC emacs-lisp
(setq gnus-message-archive-group
(("Tiger" "nnimap+tiger:Tiger/sent")
("Gmail" "nnimap+gmail:Gmail/sent")
(".*" ,(format-time-string "sent/%Y-%m"))))
#+END_SRC

The above code specifies where the sent mails are stored. Note that
=Tiger/sent= is the actual folder where sent mails are stored.
Remember that we use =nametrans= to map remote folder to local folder
with a different name? If you don't use =nametrans= feature, then
this =Tiger/sent= might be =Tiger/Sent Mails=, =Tiger/Sent Items= or
some other names.

**** Email account configuration

#+BEGIN_SRC emacs-lisp
(setq gnus-parameters
'(("Tiger.*"
(charset . utf-8)
(posting-style
(address "[email protected]")
(gcc "nnimap+tiger:Tiger/sent")
(name "Zhitao Gong")
(signature-file "tiger")
(organization "Auburn CSSE")))
("Gmail.*"
(charset . utf-8)
(posting-style
(address "[email protected]")
(gcc "nnimap+gmail:Gmail/sent")
(name "Zhitao Gong")
(signature-file "gmail")
(organization "Auburn University")))))
#+END_SRC

This above code configures each account separately, e.g, signatures,
charset, etc.

* Miscellaneous
:PROPERTIES:
:CUSTOM_ID: sec:miscellaneous
:END:

All other configurations are just for personal preference. You could
easily find their document online or through =emacs= inline manual.

* Conclusion
:PROPERTIES:
:CUSTOM_ID: sec:conclusion
:END:

Now it works.

This repo shows a /complete/ and /working/ solution of =gnus=, another
step towards *living in emacs*. It took me years to get used to
=emacs= and =gnus=, and I never regret the effort.

* Footnotes

[fn:1] Actually *virtual folders*, since all mails in Gmail are stored
in *All Mail* folder, other folder names are just *tags* despite that
they are visually displayed as *folders*.

[fn:2] Not *full* configuration actually, there are lots of
configuration files for =dovecot=, most of which, however, work out of
the box.