Separate identities in folders for Gnus

541ddcd gnus-identities-variables-set: Fix typo

2 years ago

New ticket tracker added

2 years ago
  1. gnus-identities
    1. Introduction
    2. Installation
    3. Getting Started
    4. How does it work? What does it do?
    5. Mapping of variables, packages, and file locations (old and new)
    6. Structure of identity (id) folder tree
    7. Roadmap
    8. Appendix - Related Software and References




"Identities" are not just separate email addresses, but entirely separate persona (although sill under the same user at the Emacs and OS levels) whos data and configs1 you would like to keep in completely separate folders for whatever reason:

  • Maybe you want to connect from distinct IP addresses per identity2, or

  • Sync the folders per identity to different locations, or

  • Maybe you just prefer to have Gnus settings put away nicely according to XDG Base Directory Specification, instead of having them all over your home directory, or

  • … ?

I suppose this is somewhat akin to the concept of "profiles" in browsers like Firefox and Chromium.

This package provides a launcher to start Gnus with only one of the identities at a time, selecting it from a list.

It also follows (by default) a folder scheme which adheres to the XDG Base Directory Specification (unlike Gnus itself).


I have not bothered to submit this to any package repos (yet). I am not even sure anyone but myself will use it. So for the time being, simply:

  1. Clone the repo somewhere on your local machine (this makes updating easier):

    ~/git/ext $ git clone https://git.sr.ht/~trs-80/gnus-identities
  2. Add the path to your Emacs load path3:

    (add-to-list 'load-path "~/git/ext/gnus-identities")
  3. Add something like the following to your init file:

    (require 'gnus-identities)

#Getting Started

  1. (Optional) Set values for the following variables (or leave defaults, which follow XDG Base Directory Specification):

    Variable Default
    gnus-identities-basedir-config ~.config/gnus/
    gnus-identities-basedir-data ~.local/share/gnus/
  2. Create one or more identities with the function gnus-identities-create.

    1. N.B.: This only creates the required (empty) directory structures. You will still need to create a .gnus.el file to hold your settings, for each new identity. Your newly created config directory will be opened in dired to help facilitate this.
  3. ONLY if you DO already have existing Gnus configs and/or data:

    1. Make sure you have exited from any running Gnusae.

    2. Move all the files (and dirs) in the table below to their new locations (assuming defaults).

  4. Invoke gnus-identities-launcher and choose an identity.

  5. This function will set some things (according to the identity you have chosen), and then start Gnus.

#How does it work? What does it do?

  1. Essentially, gnus-identities-launcher does the following:
    1. Present you with a list of identities to choose from.

    2. setq several variables to their identity specific values (mostly directory locations, see table below).

    3. Launch Gnus.

#Mapping of variables, packages, and file locations (old and new)

  • N.B.: that id in path (last column, below) expands according to explanation in following section.
Variable Package File / dir Nature Original loc New (default) loc
gnus-home-directory gnus dir base dir ~/ $XDG_CONF/id/
[1] gnus .gnus.el config ~/.gnus.el $XDG_CONF/id/.gnus.el
(data) [3]          
gnus-directory gnus dir data ~/News/ $XDG_DATA/id/news/
message-directory message dir data ~/Mail/ $XDG_DATA/id/mail/
gnus-startup-file gnus .newsrc state/data ~/.newsrc $XDG_DATA/id/.newsrc
[2] gnus .newsrc.eld state/data ~/.newsrc.eld $XDG_DATA/id/.newsrc.eld
  • Notes for above:

    1. Near as I can tell, there is no way to set the location of this file explicitly, and it just gets placed in gnus-home-directory.

    2. Near as I can tell, there is no way to set the location of this file explicitly, and it just gets placed in same location as gnus-startup-file.

    3. N.B.: that Gnus makes no distinction between user data and config, and (by default) places everything in gnus-home-directory. We change this paradigm and actually prepend $XDG_DATA_HOME (see default location below) to not only our data directories, but also the location of gnus-startup-file, as the full path would otherwise be encoded in Gnus' default value (~/.newsrc).

  • Abbreviations for above:

    Abbreviation Expanded Default
    $XDG_CONF $XDG_CONFIG_HOME ~/.config/
    $XDG_DATA $XDG_DATA_HOME ~/.local/share/

If you prefer to look at Elisp, you can see the above mapping implemented in the function gnus-identities-variable-set.

#Structure of identity (id) folder tree

As explained in the docstrings for the variables gnus-identities-basedir-* (which are the (2) base directories containing the folder trees):

This directory contains folders which are hostnames. Inside the hostname folders are user names (in the email sense). Inside those are the configs4 per identity / email address.

For example: ~.config/gnus/example.com/user/ would be the config4 folder for the email / identity user@example.com.

  • N.B.: that there are (2) folder trees / basedirs, one for config and one for data:
    • gnus-identities-basedir-config
    • gnus-identities-basedir-data

Or, put visually (using tree):

Say you have 4 identities (email addresses):

  • user_a@example.org
  • user_b@example.org
  • user_c@example.net
  • user_d@example.com

The id folder tree (inside basedir) would look like:

├── example.org
│   ├── user_a
│   └── user_b
├── example.net
│   └── user_c
└── example.com
    └── user_d


This package is already usable to me as-is. However there are a few more things I would like to do eventually(TM) to smooth over some rough edges. In roughly descending order of priority / likelyhood, they are:

  • [X] Implement a function which will, when given a new email address (identity), automatically create new identity folder trees, following the proper folder structure.

  • [X] gnus-identities-launcher: Implement code to dynamically generate the list of identities to choose from, based on the directory structure in gnus-identities-basedir-config.

  • [ ] Add some hooks, in particular:

    • [ ] An identity-verify hook which will be called after selecting an identity, but before launching Gnus.
      • In here you could for example verify that your external IP address is what you think it is, before continuing. As this is my original and primary use case, I am sure I will eventually put some Elisp in contrib/ implementing this.
  • [ ] Make the folder names in gnus-identities-basedir-data (i.e., news/ and mail/) user configurable (currently they are hard coded).

  • [ ] Implement gnus-identities-variables-unset (and related hook(s)). In the meantime, as long as you always use gnus-identities-launcher, all the relevant variables will be overwritten at each launch, so it doesn't really matter (I think?).

  • Prior art, similarly named, and/or related packages (and how they differ):

    • GnusAlias

      • "Provides a simple mechanism to switch Identities when using message-mode (things like From, Organization, extra headers, Body, Signature)."

      • Differs in that it does not offer near as much isolation of the identities as this package.

    • GnusPers

      • "gnus-pers implements personalities for Message mode. It allows you to define a personality with any e-mail address, extra headers and signature you like, either as strings, functions or variables (signatures may also be files). Then it will chose a personality for you based on header info, gnus-newsgroup-name or group parameter. Additionally, you can change a personality in the middle of writing a message. This is intended to be an alternative to gnus-posting-styles, which only sets personalities (posting styles) based on which group you are in."

      • Differs in that it does not offer near as much isolation of the identities as this package.

  • Reference:


1 For email and news only. This is intended for switching Gnus init files, not Emacs (for the latter, there is chemacs).

2 This was my original use case. As nnimap will apparently keep a connection alive to each server, I did not want to have all my identities together in one instance of Gnus.

3 I actually keep all my (external) Elisp repos in ~git/ext/elisp/, so I can just do the following, which automatically adds everything in there to the load path:

(let ((default-directory "~/git/ext/elisp"))

4 In gnus-identities-basedir-data it will say "data" here instead. Also the path will be different (see table).