Super User is a question and answer site for computer enthusiasts and power users. 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 am using Mutt, and I have a message in my inbox with around ~1000 attachments, about 50% of which are .jpg files. I want to save all of those to a specified directory, leaving the other attachments alone.

Is it possible to do this easily with a few keystrokes or commands? Shift+T appears to allow for pattern-based tagging for messages, but not attachments.

share|improve this question
up vote 3 down vote accepted

You can tag (t) messages with attachments then send messages through a pipe (;|) program to extract attachments. I suggest you to set the following config in your .muttrc

set pipe_split = yes # sends tagged messages 1by1 otherwise they're concatenated with $pipe_sep
unset pipe_decode    # don't strip headers and eval mimes when piping

I wrote a really raw (WIP never finished but works...) ruby script to extract attachments. You can inspire yourself with it...

#!/usr/bin/env ruby
#
# scriptname : ~/bin/mutt_utils.rb
#
# Messages tagged
# To work with tagged message you have to :set pipe_split
# Otherwise only first message tagged will be processed.
#
require 'optparse'
require 'fileutils'
require 'mail'
#
# monkeypatch Mail::Message class to fix Invalid byte sequence with ruby 1.9
# https://github.com/mikel/mail/issues/340
# https://github.com/mreinsch/mail/commit/c7818a95f9f9fddc675f75452ea5000c46c30d94
#
if RUBY_VERSION >= "1.9.1"
  class Mail::Message
    def raw_source=(value)
      value.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
      @raw_source = value.to_crlf
    end
  end
end

options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: #{File.basename $0} [OPTIONS]"
  opts.on("-o", "--output PATH", "save in PATH folder") do |path|
    options[:output] = path
  end
  opts.on("-O", "--overwrite", "overwrite existing files") do |owr|
    options[:overwrite] = owr
  end
  opts.on("-n", "--name-regexp PATTERN", "save only attachment's name matching PATTERN") do |pat|
    options[:name_pattern] = pat
  end
  opts.on("-c", "--content-regexp PATTERN", "save only attachment's content_type matching PATTERN") do |pat|
    options[:content_pattern] = pat
  end
  opts.on("-v", "--verbose", "verbose") do |v|
    options[:verbose] = v
  end
  opts.on("-h", "--help", "usage") do
    puts opts
    exit
  end
end.parse!
puts "Options passed : #{options}" if options[:verbose]

if options[:output]
  unless File.directory?(options[:output])
    $stderr.puts "'#{options[:output]}' is not a valid folder !"
    exit
  end
end

def sanitize(value)
  value.gsub(/\s/, '_').gsub(/:/, '-').gsub(/\//, '-').gsub(/\\/, '-')
end

def check_criteria(criteria, pattern)
  return true if pattern.nil?
  criteria =~ /#{pattern}/i
end

data = ARGF.readlines.join
mail = Mail.read_from_string data #.force_encoding("UTF-8")
ts = mail.date.strftime("%Y-%m-%dT%H%M")
puts "Processing mail '#{mail.subject}' " if options[:verbose]
subject = mail.subject.nil? ? 'no subject' : mail.subject.downcase

mail.attachments.each do |att|
  puts "Attachment : filename=#{att.filename} content_type=#{att.content_type}" if options[:verbose]
  valid_name = check_criteria(att.filename, options[:name_pattern])
  valid_content = check_criteria(att.content_type, options[:content_pattern])
  unless valid_name
    puts "Filename doesn't match #{options[:name_pattern]}" if options[:verbose]
  end
  unless valid_content
    puts "Content doesn't match #{options[:content_pattern]}" if options[:verbose]
  end
  next unless ( valid_name && valid_content )
  fn = sanitize "#{ts}_#{subject}_#{att.filename}"
  fn = File.join(options[:output], fn) if options[:output]
  puts "Saving attachment to #{fn}." if options[:verbose]
  if (!options[:overwrite] && File.exist?(fn))
    $stderr.puts "'#{fn}' already exists ! Skipping." if options[:verbose]
    next
  end
  begin
    File.open(fn, 'wb') {|f| f.write att.body.decoded }
  rescue Exception => e
    $stderr.puts "Error while saving #{fn} ! Cause: #{e.message}"
  end
end

Don't forget to chmod +x ~/bin/mutt_utils.rb.

Usage sample: tag some messages with attachments, hit ; then |.

Enter at prompt ~/bin/mutt_utils.rb -o ~/Desktop/.

You should now find your attachments on your desktop.

share|improve this answer
    
for extracting only jpeg, use the -c or -n switch option. – undx Jan 6 '13 at 14:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .