Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I use this line for images in my mailcap:

image/*; eog %s &;

but mutt immediately deletes the temp file and eog can’t load it.
When I remove the & mutt waits for eog to be closed until it escapes from the command line.

share|improve this question
up vote 2 down vote accepted

Here's what I use:


application/*; mkdir -p /tmp/mutt \; cp %s /tmp/mutt \; xdg-open /tmp/mutt/$(basename %s) &


folder-hook . `rm -f /tmp/mutt/*`

Every time an attempt to open an attachment is made, it's copied in a dedicated temp directory and the copy is opened.
Every time you start mutt, any lingering copies are cleaned up.

You may or may not need the & at the end, depending on the command you used. (Some versions of xdg-open are blocking, while others are not.)

Needless to say, you can use this with any command. xdg-open is just a convenient one-stop handler.

share|improve this answer
This is a cool general way to replace mailcap! Thanks! – Profpatsch Jan 17 '14 at 11:02
I needed the & after xdg-open. Can’t hurt to have it there in any case, right? – Profpatsch Jan 17 '14 at 11:06
Maybe you could make a question: How to replace mailcap with xdg-open? and copy that answer over. I’m sure there are some people with that question. – Profpatsch Jan 17 '14 at 11:09
Wouldn't this be problematic if you have multiple applications opened by mutt changing folders would wipe out anything in your /tmp/mutt/ folder. Since xdg-open might or might not block I'm just using the application (firefox) text/html; t=$(mktemp /tmp/XXXXXXXXXX) \; cp %s "$t" \; /bin/sh -c "firefox $t \; rm $t \;" & – Derek Schrock Apr 21 '15 at 15:22

You could use a wrapper command that:

  1. renames the file
  2. runs the viewer in background
  3. cleans up when the viewer has returned instead of letting mutt do it.

Something like:

#! /bin/sh -

  mutt -D 2> /dev/null |
    awk -F\" '
      $1 == "tmpdir=" {
        gsub("~", ENVIRON["HOME"], $2)
        print $2
[ -n "$TMPDIR" ] || exit
export TMPDIR

for i do
  case $i in
      new_file=$(mktemp -ut "XXXXX${i##*/}") &&
        mv -- "$i" "$new_file" &&
        nfiles=$(($nfiles + 1)) &&
        set -- "$new_file" "$@" "$new_file" &&
  set -- "$@" "$i"

run_command() (
  shift "$(($nargs + $nfiles))"
  exec "$@"

  run_command "$@"
  while [ "$nfiles" -gt 0 ]; do
    set -- "$@" "$1"
    nfiles=$(($nfiles - 1))
  shift "$((2*$nargs))"
  rm -f -- "$@"
) &

And put something like:

image/*; muttv eog %s;

Where muttv is that script above.

The above makes no assumption on where the filename(s) appear(s) in the list of arguments or what character they contains... Which is why we first ask mutt what its tmpdir is (so we use that to determine what are the files to view).

In most cases, it would be overkill though, and as Gilles points out may not work if tmpdir is specified as relative to your mailbox folder.

A simpler one would be:

#! /bin/sh -
eval "file=\${$nargs}"
newfile=$(dirname -- "$file")/new-$(basename -- "$file")
while [ "$nargs" -gt 1 ]; do
  set -- "$@" "$1"
  nargs=$(($nargs - 1))
mv -- "$file" "$newfile" || exit
  "$@" "$newfile"
  rm -f -- "$newfile"
) &

Replace mv with cp if you don't want to touch the original file provided by mutt.

share|improve this answer
Gosh, did you just write that from scratch? It took me 15 minutes to understand what you are doing and even now I’m not sure about how some parts work exactly. – Profpatsch Feb 20 '13 at 0:19
Fails with my .muttrc because tmpdir="=tmp". Why not grab the directory from the file name? – Gilles Feb 20 '13 at 19:53
@Gilles, good point about the "+", "="... The whole point was to get tmpdir from mutt so we know which of the arguments is the file name. The whole thing is a bit overkill though anyway as in 99% of the cases the filename is going to occur only once and be the last argument, and we can just rename it to new-$original – Stéphane Chazelas Feb 20 '13 at 19:58
Another point is that this entry script isn't always called on behalf of mutt, it could be called in circumstances where the file isn't a temporary file and must not be deleted. (I often call see on the command line, I don't expect it to remove the file, even if it's in /tmp!) Solution: make a hard link. – Gilles Feb 20 '13 at 20:03
@Gilles, I thought of the hardlink, but for mutt, it doesn't work, because after running the command, mutt truncates the file before unlinking it. (open with O_TRUNC and close, I did verify it). – Stéphane Chazelas Feb 20 '13 at 20:30

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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