Running Mailcatcher
MailCatcher can be used in development where you do not have access to an SMTP server but need to see the email being sent - in HTML format.
I started installing mailcatcher
(on MacOS 13.2, Apple Silicon, Ruby 3.1.0 - rbenv) with:
gem install mailcatcher
…and it said, “No.”
➜ mailcatcher git:(main) ✗ gem install mailcatcher
Building native extensions. This could take a while...
ERROR: Error installing mailcatcher:
ERROR: Failed to build gem native extension.
current directory: /Users/nitin.katkam/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/thin-1.5.1/ext/thin_parser
/Users/nitin.katkam/.rbenv/versions/3.1.0/bin/ruby -I /Users/nitin.katkam/.rbenv/versions/3.1.0/lib/ruby/3.1.0 -r ./siteconf20230213-91740-6cxo7o.rb extconf.rb
checking for main() in -lc... yes
creating Makefile
current directory: /Users/nitin.katkam/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/thin-1.5.1/ext/thin_parser
make DESTDIR\= clean
current directory: /Users/nitin.katkam/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/thin-1.5.1/ext/thin_parser
make DESTDIR\=
compiling parser.c
parser.rl:112:17: warning: comparison of integers of different signs: 'long' and 'unsigned long' [-Wsign-compare]
assert(pe - p == len - off && "pointers aren't same distance");
~~~~~~ ^ ~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/assert.h:99:25: note: expanded from macro 'assert'
(__builtin_expect(!(e), 0) ? __assert_rtn(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0)
^
MailCatcher uses Thin 1.5.1 and it doesn’t seem to be working for me. I tried to install the latest version of Thin with gem install thin
and it installed version 1.2.7 normally. I decided to clone the GitHub repo and bump up the version for a try - but then I see that there was an update to the mailcatcher.gemspec file to use the newer version of thin
so that seemed promising.
git clone https://github.com/sj26/mailcatcher.git
cd mailcatcher
gem build mailcatcher.gemspec
I wanted to try the gem by just keeping it in a local subdirectory so:
mkdir .gem
export GEM_PATH=$(pwd)/.gem
gem environment # I ensured that I have the $GEM_PATH among the 2 listed here
gem install mailcatcher-0.9.0.beta2.gem --install-dir $(pwd)/.gem
.gem/gems/mailcatcher-0.9.0.beta2/bin/mailcatcher
…and the server came to life
Starting MailCatcher v0.9.0.beta2
==> smtp://127.0.0.1:1025
==> http://127.0.0.1:1080
*** MailCatcher runs as a daemon by default. Go to the web interface to quit.
Trying to avoid doing anything from the GUI, I try to load the URL from the command line with:
"$(find /Applications/Google\ Chrome.app/Contents/ -type f -perm +111 | head -n 1)" https://www.google.com
…and then I see text on white background - something stopped the CSS and Javasript from loading. The Google Chrome inspector indicated that it was because it received content of type text/html
instead of text/css
and application/javascript
and with strict MIME type checking, it would not execute them. I spent the next couple of minutes trying to lookup how to specify the MIME type in a Sinatra web application with Sprockets, and I didn’t see where I had to make the changes in the MailCatcher source code (lib/mail_catcher/web
has 2 files - application.rb
and assets.rb
). I decided to check if somebody had reported the issue and, sure enough, there was #299 explaining the exact issue I was experiencing. Apparently, the right way to build the gem is to use bundle exec rake assets; bundle exec rake package
so I start with a cleanup:
➜ mailcatcher git:(main) ✗ gem uninstall -i /Users/nitin.katkam/Documents/landd/rubyProjects/mailcatcher/.gem mailcatcher
Remove executables:
mailcatcher, catchmail
in addition to the gem? [Yn]
Removing mailcatcher
Removing catchmail
Successfully uninstalled mailcatcher-0.9.0.beta2
…followed by:
bundle exec rake assets; bundle exec rake package
gem install mailcatcher-0.9.0.beta2.gem --install-dir $(pwd)/.gem
.gem/gems/mailcatcher-0.9.0.beta2/bin/mailcatcher
and then there was color. I ran a quick test with telnet localhost 1025
, crafted an email, sent it, and received it in MailCatcher.
I then go to a Windows laptop, proceed with the install with a gem install mailcatcher
and I see:
current directory: C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/eventmachine-1.0.9.1/ext/fastfilereader
...
C:/Ruby30-x64/msys64/mingw32/include/rpcndr.h:64:11: error: reference to 'byte' is ambiguous
I installed the latest EventMachine with gem install eventmachine
and observed version 1.2.7 had installed normally, so I bump up the version in the mailcatcher.gemspec and attempt to proceed. It built successfully.
But upon trying to run mailcatcher
, I get a:
Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby'
So, I go to C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/eventmachine-1.2.7-x64-mingw32/lib/rubyeventmachine.rb
(found after I looked up the location of the gem with gem which eventmachine
) and prepend a require 'em/pure_ruby
to the top… which gives me:
C:/Ruby30-x64/lib/ruby/3.0.0/set/sorted_set.rb:4:in `rescue in <top (required)>': The `SortedSet` class has been extracted from the `set` library.You must use the `sorted_set` gem or other alternatives. (RuntimeError)
from C:/Ruby30-x64/lib/ruby/3.0.0/set/sorted_set.rb:1:in `<top (required)>'
So, I gem install sorted_set
and try again. Now:
C:/Ruby30-x64/lib/ruby/3.0.0/set.rb:373:in 'delete': can't modify rbtree during iteration (TypeError)
In the EventMachine GitHub repo, I see this as #927 and closed in PR 929 on September 6, 2020. EventMachine 1.2.7, which is the latest as of February 2023, was released on May 12, 2018 so obviously doesn’t have the needed fix. I manually replace the function with the replacement provided in the issue by @wordjelly and that fixes the error.
But then there’s another one:
C:/Ruby30-x64/lib/ruby/gems/3.0.0/eventmacine-1.2.7-x64-mingw32/lib/em/pure_ruby.rb:559:in 'close': Bad file descriptor (Errno::EBADF)
That’s about as far as I was able to go on Windows 10. With RedHat Enterprise Linux 8.7 being my target environment, I decided to abandon the effort of trying to get MailCatcher working on Windows.
Now, on RedHat Linux 8.7, I install RVM and the install works normally (I had to use the alternate commands provided to import the gpg keys). I then install development tools with dnf groupinstall "Development Tools"
and I try to install mailcatcher. I again have a problem because the psych
gem needs the yaml.h
file to compile. I have the libyaml
package on RHEL but I don’t have the libyaml-dev
package available in the repo.
For RedHat 6 and 7, libyaml-dev
used to be available in the rhel-x-server-optional-rpms (where “x” is 6 or 7) but, with RedHat 8, the repository structure changed and (some?) “-devel” packages moved to the codeready-builder-for-rhel-8 repository. In RedHat 8, the Base OS, App Stream and Code Ready repos together should have all that you need. To enable the CodeReady repo:
subscription-manager repos --list | grep 'Repo ID' # Look at the Repo ID here
subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms
dnf install -y libyaml-devel
Success! I then proceed trying to build the mailcatcher gem when I get to:
bundle exec rake assets
rake aborted!
ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime
I see with dnf search node
and dnf info nodejs
that the RedHat repo has version 10.24.0 of NodeJS, which is old. I then decided to use asdf, a package manager for Ruby, Node.js, Elixir and Erlang to install NodeJS.
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.11.1
echo '. "$HOME/.asdf/asdf.sh"' >> ~/.bashrc
source ~/.bashrc
asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
asdf list all nodejs
asdf install nodejs 18.14.0
asdf global nodejs 18.14.0 # Use "latest" instead of a version number if you like to live dangerously
# If you don't want to make it the global default, use: asdf local nodejs 18.14.0
I had to set the TMPDIR
before running asdf install nodejs 18.14.0
because of:
asdf install nodejs 18.14.0
Clining node-build...
node-build: TMPDIR=/tmp cannot hold executables (partition possibly mounted with `noexec`)
At the end, I got mailcatcher running on MacOS and Linux. EventMachine in pure Ruby hasn’t been as actively maintained so we couldn’t get it running on Windows.
PS: To setup mailcatcher with less pain, use the Docker image.