What it is

emacs-mailto makes macOS mailto: links open in Emacs, using whatever mail-user-agent you already have configured — mu4e, notmuch, Gnus, Rmail, or plain message-mode. Click a mailto: link in your browser, and Emacs comes to the front with a compose buffer already addressed.

The project lives at sr.ht/~bounga/emacs-mailto, where you’ll find the source and the ticket tracker.

The problem it solves

The GNU Emacs NS port — as shipped by emacs-plus, emacs-mac, or the official build — does not handle mailto: URLs.

When Emacs is already running, clicking a mailto: link activates Emacs but the URL never arrives: macOS brings the app to the front and drops the URL Apple-event before it ever reaches Emacs Lisp. So nothing happens — no compose buffer — and there is no way to fix it from your config, because the event never gets there in the first place.

That’s the whole frustration emacs-mailto exists to remove.

How it works

emacs-mailto sidesteps the dropped Apple-event with a tiny relay app registered as your default mail application. On a mailto: click, it brings Emacs to the front and hands the URL to emacsclient:

open -a Emacs
emacsclient -n -e "(run-at-time 0 nil (lambda () (browse-url-mail \"<url>\")))"

browse-url-mail parses the mailto: URL — recipient, subject, body — and opens a compose buffer through your mail-user-agent. The run-at-time wrapper lets emacsclient return immediately instead of blocking on an interactive prompt, such as a From-address picker.

A few details make it painless in practice:

  • emacsclient is located automatically at runtime (Homebrew on Apple Silicon or Intel, MacPorts, ~/.local/bin, or /usr/bin), so no path is hard-coded.
  • The app is built and ad-hoc signed locally by the installer, so there is no Gatekeeper quarantine and no pre-built binary to trust.

Requirements

  • macOS
  • Emacs running with a server (M-x server-start, or the Doom/Spacemacs defaults), so emacsclient can reach it
  • A configured mail-user-agent — this is what actually opens the compose buffer

Installation

Clone the repository and run the installer:

git clone https://git.sr.ht/~bounga/emacs-mailto
cd emacs-mailto
./install.sh

This compiles Emacs Mailto.app into ~/Applications, registers it, and sets it as the default mailto: handler.

Test it:

open "mailto:test@example.com?subject=Hi"

Emacs should come to the front with a compose buffer addressed to test@example.com.

If your Emacs app has a different name, or you want a custom bundle identifier, override them with environment variables:

EMACS_APP="Emacs" BUNDLE_ID="org.nongnu.emacs-mailto" ./install.sh

A caveat about the default mail app

The relay runs as a background agent (LSUIElement), so it does not show up in Mail → Settings → General → “Default email application”. That menu may keep displaying another app — ignore it. To check the real handler, ask LaunchServices directly:

swift -e 'import AppKit; print(NSWorkspace.shared.urlForApplication(toOpen: URL(string:"mailto:x@y.z")!)!.path)'

It should print .../Emacs Mailto.app.

Uninstall

./uninstall.sh

This removes the app and resets the mailto: handler to Apple Mail.

Wrapping up

That’s the whole tool — a small relay that removes a long-standing papercut of running Emacs as a mail client on macOS. It’s MIT licensed. If you hit a rough edge with your particular Emacs build or macOS version, the tracker is on the project page at sr.ht/~bounga/emacs-mailto.

Have comments or want to discuss this topic?

Send an email to ~bounga/public-inbox@lists.sr.ht