My name is Jeaye

I'm a leader, a problem solver, and a hacker with a passion for privacy and security.

A RainLoop review and setup guide

RainLoop is a web-based MUA similar to Roundcube, Mailpile, and the like. When looking to setup portable email access for my wife, who no longer is happy with just Thunderbird, RainLoop seemed like a reasonable choice. Here are some integration notes, as well as a review and some ranting, based on my afternoon setting it up.

UI and functionality

My wife has been tolerating RainLoop, on both desktop and mobile. A number of annoyances have occurred, most of which are minor, but the sum of which is significant.

  • There is no auto refresh on desktop or mobile. The refresh button needs to be clicked in order for mail to be checked. This requires conscious effort to regularly check the mail, rather than be notified when something arrives in the inbox.

  • On mobile, the back button doesn’t behave properly; after selecting an email, the back button will not return to the inbox. After hitting it, failing, and manually returning to the inbox, the search will have been changed to is:flagged.

    Unfortunately, it’s more buggy than that. After asking her to reproduce it for me a second time, she was in her inbox, selected an email, and the back button then brought her to the settings menu. For now, she’s just not using that button.

  • On mobile, the hamburger menu (as it is on desktop) is missing. This means it’s impossible to mark emails as Read or Flagged. Handy features like Mark all as read, which live in that hamburger menu, are also not present. This does further cripple the mobile version.

  • There is no autocompletion of names or emails, based on existing emails in one’s inbox. Instead, it seems that they may need to be added to the contacts list. Manually adding each contact is tiresome, tedious work and the completion of emails and names in the To, Cc, etc forms should be filled in a smart way.

  • The refresh icon, in the inbox view, is entirely unintuitive; neither of us knew what it was supposed to do when we first saw it. It’s not a tough thing to learn, but that doesn’t seem like the place we should be breaking new ground.

  • While there are default themes, none of them change the color of the message body background, which remains a glaring white. Some more complete default themes would be appreciated, for those with sensitive eyes.

  • As an admin, there’s no clear way of knowing if the Community or Standard version of RainLoop is installed. From what I’ve seen, the best way is to go to the admin page, then to the About section. If you see anything, under the version, about licensing and subscriptions, you’re on the Standard version. If you see nothing, you’re on the Community version. This should be made more clear.

  • There is absolutely no community to be found. No forums, no IRC channel, Gitter, Slack, etc. Ironically, no mailing list either. There is only a support email, where one can contact the RainLoop devs. This is unsettling.

There are a couple of features and positive points which are worth noting. While the critical feedback is more vocal, RainLoop does have some much appreciated aspects.

  • The ease of setup should not be understated and is much appreciated. Aside from unzipping and setting up Apache, nothing is required. The default config is no config and that’s both comforting and somewhat unsettling.

  • The admin console is simple and effective, though it could provide more information on what each option actually does.

  • The support for “smart” multiple identities would’ve been sorely missed, but it behaves exactly as one would expect. For an example, my wife has multiple emails, each one using a different name. It’s possible to select the default profile to use, when composing without replying. Aside from that, RainLoop will automatically use the profile which matches the To of any email she receives. So, she can always just reply and RainLoop will use the correct profile, name, and ReplyTo.

  • While more complete themes would be appreciated, the presence of themes out of the box is a nice touch.

Community vs Standard version

The website for RainLoop is quite minimal, but so is the setup itself. The biggest decision one needs to make is whether or not to use the Community (AGPL) version or the Standard (closed-source) version. As of writing, for personal sites, the Community version lacks only one feature: single-click updating. Instead, the user is directed to install the new version atop the old one, manually.

No single-click updating?

As far as licensing is concerned, that’s not a problem at all. The approach where the core of a product can be open source, while some non-crucial features cost money, is a pretty reasonable deal. Still, there’s no need to use a closed-source version just to get single-click updating. Manually updating in-place, however, is error-prone, non-atomic (meaning it’s not all or nothing), imperative, and not the NixOS way. We can do better.

Basic installation

Following the documentation, basic installation is a breeze.

Note: The below uses /var/www/rainloop, but this could be anywhere on your machine which is capable of serving data to Apache.

Download and unzip

$ wget http://www.rainloop.net/repository/webmail/rainloop-community-latest.zip
$ mkdir /var/www/rainloop
$ unzip rainloop-community-latest.zip -d /var/www/rainloop

Hook into Apache

From there, a basic Apache setup can just look in the rainloop directory.

<Directory /var/www/rainloop>
  DirectoryIndex index.php
  Options -Indexes +ExecCGI
  AllowOverride All
  Order deny,allow
  Allow from all
  Require all granted
</Directory>

As per the documentation, all configuration, caches, and assorted private data is included within the top-level rainloop directory, but within a data directory. Ideally, no users should be able to access that, so it should be disabled within Apache.

<Directory /var/www/rainloop/data>
  Options -Indexes
  Deny from all
</Directory>

Aside from setting up HTTPS, which should be considered a requirement for any web application, that’s it. As per the docs, manual upgrading involves unzipping the newest release on top of the live version. As per the intro, we can do better.

Automatically and atomically updating

The RainLoop devs are kind enough to package a PGP signature for each release. Using a script, it’d be straightforward to compare that signature with the one of our live version. If the two differ, we can assume a new version has been released. The new version can be downloaded and extracted in a new directory (copied from the live one). The new signature should be kept in the new directory, so the script can know when the next update arrives. Once the new setup is complete, a symbolic link can be atomically updated to point to the latest version.

Directory layout

The current directory layout, as per the basic installation is similar to this.

$ tree -L 1 /var/www/rainloop
/var/www/rainloop
├── data
├── index.php
└── rainloop

Instead, each version can be dated. RainLoop doesn’t have specific version numbers in its release zips, so the date is the next easiest thing to use. The latest link will just point to the latest version. Since RainLoop isn’t very large (about 25MB), it likely doesn’t hurt to keep these versions around. If it does, a simple daily cron can clean up all but the last N versions. Here’s an example of what the new setup would look like.

$ tree -L 2 /var/www/rainloop
/var/www/rainloop
├── latest -> /var/www/rainloop/version-2017-04-23.19:09:29
├── version-2017-03-01.13:14:11
│   ├── data
│   ├── index.php
│   ├── rainloop
│   └── rainloop-community-latest.zip.asc
├── version-2017-04-21.13:03:58
│   ├── data
│   ├── index.php
│   ├── rainloop
│   └── rainloop-community-latest.zip.asc
└── version-2017-04-23.19:09:29
    ├── data
    ├── index.php
    ├── rainloop
    └── rainloop-community-latest.zip.asc

Upgrade script

With the theory out of the way, here’s a working upgrade script which follows all of the above ideas. It can be run manually, in a cron job, or perhaps hooked into NixOS’ activation scripts. If no upgrade is available, since the live signature matches the latest one on the RainLoop downloads page, the script does nothing.

#!/usr/bin/env bash

set -eu -o pipefail

# The only thing you'll need to change
local_webmail=/var/www/rainloop # Wherever you're running rainloop

zip_file=rainloop-community-latest.zip
signature_file=$zip_file.asc
remote_webmail=https://www.rainloop.net/repository/webmail

printf "RainLoop: checking for upgrades... "
new_zip_signature=$(curl -s "$remote_webmail/$signature_file")
old_zip_signature=$(cat "$local_webmail/latest/$signature_file" || true)

if [ "$new_zip_signature" != "$old_zip_signature" ];
then
  echo "found"
  echo "RainLoop: upgrading..."
  temp_dir=$(mktemp -d)
  pushd "$temp_dir"
    gpg2 --import <(curl -s "https://www.rainloop.net/repository/RainLoop.asc")

    # Download new version
    wget "$remote_webmail/$zip_file"
    gpg2 --verify <(echo "$new_zip_signature") "$zip_file"

    # Start from the latest, if it's there
    if [ -d "$local_webmail/latest" ];
    then
      rsync -av "$local_webmail/latest/" .
    fi

    unzip -o "$zip_file"
    rm "$zip_file"

    echo "$new_zip_signature" > "$signature_file"
  popd

  new_version=$(date +'version-%Y-%m-%d.%H:%M:%S')
  new_path=$local_webmail/$new_version
  if [ -d "$new_path" ];
  then
    echo "RainLoop: directory already exists: $new_path"
    exit 1
  fi

  # Move the new version into place and setup permissions
  mv "$temp_dir" "$new_path"
  find "$new_path" -type d -exec chmod 755 {} \;
  find "$new_path" -type f -exec chmod 644 {} \;
  chown -R http:users "$new_path"

  # Atomically link/upgrade
  ln -sfn "$new_path" "$local_webmail/latest"

  echo "RainLoop: upgrade complete"
else
  echo "not found"
fi

Apache tweaks

The only tweak needed is in the Apache config. Apache should just point at the latest link, so upgrading will never require changing its configs. That link needs to be followed, so +FollowSymLinks should be added, too. Since the upgrade is atomic (all or nothing), Apache won’t ever be serving up a half-upgraded RainLoop. It’s either fully on one version, or fully on another. This is just like NixOS and the way the Nix package manage works.

# Each directory has 'latest' at the end now
<Directory /var/www/rainloop/latest>
  DirectoryIndex index.php
  # Following symbolic links is allowed here
  Options -Indexes +FollowSymLinks +ExecCGI
  AllowOverride All
  Order deny,allow
  Allow from all
  Require all granted
</Directory>
<Directory /var/www/rainloop/latest/data>
  Options -Indexes
  Deny from all
</Directory>

A matter of security

Last, but absolutely not least, is RainLoop’s GPG support. It was originally implemented as per this issue. The problem is, it’s implemented entirely client-side, with the private key being stored in the browser. Each RainLoop session, you upload your GPG private key so that you can encrypt/decrypt/sign properly. As a matter of portability, this is terribly inconvenient.

As a matter of security, the current implementation has a number of issues, ranging from the inability to verify GPG signatures, to the storage of encrypted drafts in plain text, to the visibility of other users’ private keys, since they’re just stored in the browser. To make matters worse, the developers of RainLoop consistently close GPG-related issues, without comment (see here, here, here, here, and here). Those which are not closed are often left unaddressed for years.

As such, I cannot possibly recommend that anyone use RainLoop’s GPG implementation. Until Mailpile is stable, at least, RainLoop provides a usable webmail application. Don’t expect to get your security kicks here though, and don’t expect to find a community.