Cuttlefish is a lovely, easy to set up transactional email server
Sending a few emails from your app is easy. Sending lots becomes painful. There are so many hidden gotchas. Do your emails get delivered? Are you being considered a spammer? What about all those bounced emails?
Let's make sending lots of emails fun again!
And without the hidden dangers of vendor lock in of commercial transactional email services.
Cuttlefish is in beta. It's been used in production by OpenAustralia Foundation's projects for many years and sends over a million emails per month.
Ruby, PostgresQL, Redis (2.4 or greater), Postfix
Also you need the following libraries: imagemagick, libmagickwand-dev, libpq-dev
For development, however, the only dependencies are Docker and Docker compose.
Setting up a local development environment with all the correct dependencies and moving parts is now very straightforward by using Docker.
To start with:
docker compose run web bundle exec rake db:create db:schema:load
Now add some example seed data. This will also create a site admin with email "joy@smart-unlimited.com" and password "password". You'll need these details later to sign in. Skip this step if you don't want seed data.
docker compose run web bundle exec rake db:seed
Then
docker compose up
Those steps will take a little while as they download images and build the docker containers.
When its stops spitting output to the console point your web browser at
If you've used the db:seed
task to populate the development database you can now log in using the email "joy@smart-unlimited.com" with the password "password".
For development all mail sent out by Cuttlefish will actually go to mailcatcher. To see the mailcatcher mail:
To run the tests (do that from another window):
docker compose exec web rake
We use Vagrant and Ansible to automatically set up a fresh server with everything you need to run Cuttlefish. It's a fairly complicated affair as Cuttlefish does have quite a few moving parts but all of this is with the purpose of making it easier for the developer sending mail.
These instructions are specifically for installing the server at https://cuttlefish.oaf.org.au.
Currently the setup requires a relatively old version of Ansible (2.5.0) using Python 2.7.
Create a file ~/.cuttlefish_ansible_vault_pass.txt
which contains the password for encrypting the secret values used in the deploy. The encrypted variables are at provisioning/roles/cuttlefish-app/vars/main.yml
.
Download base box and build virtual machine with everything needed for Cuttlefish. This will take a while (at least 30 mins or so)
vagrant up
Deploy the application. As this is the first deploy it will take quite a while (5 mins or so). Further deploys will be much quicker. We're using the --set-before local_deploy=true
flag to deploy to your local test virtual machine instead of production.
bundle exec cap --set-before local_deploy=true deploy:setup deploy:cold foreman:export foreman:start
Add to your local /etc/hosts
file
127.0.0.1 cuttlefish.oaf.org.au
Point your web browser at https://cuttlefish.oaf.org.au:8443/
Login at the Linode Manager
Select "Linode 8GB" at location "Fremont, CA"
Select your new Linode in the dashboard
Click "Deploy a Linux Distribution". Choose "Ubuntu 16.04 LTS" and choose a root password. Leave everything as default.
Click "Boot" and wait for it to start up
Update provisioning/hosts
with the name of your server (e.g. li123-45.members.linode.com)
Create a file ~/.cuttlefish_ansible_vault_pass.txt
which contains the password for encrypting the secret values used in the deploy. The encrypted variables are at provisioning/roles/cuttlefish-app/vars/main.yml
.
To provision the server for the first time you will need to supply the root password you chose in step 5. On subsequent deploys you won't need this. To supply this password edit the ./provision_production.sh
script and temporily add the --ask-pass
argument to the last command, then run the script:
./provision_production.sh
Update the server name in config/deploy.rb
Deploy the application. As this is the first deploy it will take quite a while (5 mins or so). Further deploys will be much quicker
cap deploy:setup
cap deploy:cold
cap foreman:export
cap foreman:restart
At this stage you might want to snapshot the disk
Make sure that DNS for cuttlefish.oaf.org.au points to the server ip address
Point your browser at https://cuttlefish.org.au
At this point you should have a basic working setup. You should be able to send test mail and see it getting delivered.
Some further things to ensure things work smoothly
Add DNS TXT record for cuttlefish.oaf.org.au with "v=spf1 ip4:your.server.ip4.address ip6:your.server.ip6.address -all"
Set up incoming email for cuttlefish.oaf.org.au (In OpenAustralia Foundation's case using Google Apps for domain). Add addresses contact@cuttlefish.oaf.org.au, bounces@cuttlefish.oaf.org.au and sender@cuttlefish.oaf.org.au
Ensure that the devise email address is set to contact@cuttlefish.oaf.org.au
Set up reverse DNS. In the Linode Manager under "Remote Access" click "Reverse DNS" then for the hostname put in "cuttlefish.oaf.org.au" and follow the instructions. This step is necessary in order to be able to sign up to receive Feedback loop emails.
One gotcha is that we're still on Capistrano 2 which doesn't apply database migrations by default on deploys.
For normal deploys
cap deploy
To rollback a failed deploy
cap deploy:rollback
To deploy and run the migrations
cap deploy:migrations
Done some development work which updates the look of the main pages? To update the screenshots
bundle exec rspec spec/features/screenshot_feature.rb
Then commit the results
If you find what looks like a bug:
If you want to contribute an enhancement or a fix: