I run mutt in tmux and when I run gpg to sign or encrypt, gpg shows a blank screen where I would expect to type my passphrase. I've straced gpg and it shows that it's hanging waiting on a socket read() (presumably from gpg-agent. What's going on here?


Short answer

If you are using bash, then Chris W.’s wrapper script is the way to go. If perchance you are using zsh, then you can exploit the ~/.zshenv startup script to set GPG_TTY from there, no need for a wrapper. Since bash does not have a similar startup script (cf. Bash Startup Files), you’ll have to use the wrapper there.

export GPG_TTY=${TTY}

Some background: Interactive and non-interactive shells

The gpg-agent expects GPG_TTY to point to the tty from where it is invoked, such that it can display its passphrase prompts in a secure manner. The GnuPG manual suggests putting the following in ~/.bashrc (or similar):

export GPG_TTY

If you invoke mutt directly from your shell, this will work: GPG_TTY will be set, mutt will pick it up and pass it to gpg when it needs to.

However, when you launch mutt via tmux’s new-window command or similar constructs, there is an important difference: Before, your mutt was in a so-called interactive shell—that is, you had a shell prompt open and launched mutt from there yourself. tmux new-window launches a non-interactive shell, since your shell is only needed to launch mutt and you won‘t be able to interact with it. In this case, bath won‘t read .bash_profile or .bashrc at all, since they are designed to set up your shell for interactive use.

zsh does pretty much the same thing: .zshrc is read for interactive shells and skipped for non-interactive ones. However, in zsh, you can supply a third startup file, .zshenv, that is read for every shell, no matter whether it is interactive or not. Therefore, if you set GPG_TTY from there, it will always be available, no matter in which way mutt is started. And since $TTY is a shell builtin variable that always points to the current tty, you can avoid the overhead of spawning a tty process every time the shell comes up.


I was launching mutt by running tmux neww mutt. mutt was inheriting the environment set in tmux. This includes $GPG_TTY which is different for the new pane in which I'm running mutt (or unset if not in the tmux environment). I wrote a wrapper called gpgtty that sets $GPG_TTY correctly for new panes.

GPG_TTY=$(tty) $*

Then I launch mutt: tmux neww gpgtty mutt. gpg works correctly after that. FYI, this is all using pinentry-curses for gpg passphrase input.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.