1

Save an email attachment automatically to map with qmail and reformime

I'm trying to move attachment automatically to another locatie with the dot-qmail file.

My .qmail file

#------------------------------------------------------------
| condredirect pdf-junkmail headermatch 'X-Spam-Status: Yes'
| reformime -X /bin/sh -c "if [ "\${FILENAME#*.}" == "pdf" ];  then cat > /home/users/name/home/$(date +%Y%m%d)_\$FILENAME; fi"
# Forward not set
# Vacation Message not set
./Maildir/

This works for a simple mail with one attachment. My questions:

  1. How can I also move the mailmessage that belongs to this attachment to a mailbox named "done".
  2. Above command doesn't work with multiple attachments in one mailmessage? How can I ajust this line to work for multiple attachments?
  3. This doesn't work if the filename contains multiple dots like "how.areyou.pdf"

Thanks for the help

Apojoost
  • 127
  • 10
  • Your quoting of the `-c shell commands` is wrong and your `==` comparison is not valid with POSIX `sh`. The filename extension extraction need two sharps `##` or it will not grab the longest match for `*` and will not work when multiple dots in filename. You need quotes when forming strings from a variable. Here is a fixed version: `| reformime -X /bin/sh -c 'if [ "${FILENAME##*.}" = "pdf" ]; then cat > "/home/users/name/home/$(date +%Y%m%d)_\$FILENAME"; fi' ` – Léa Gris Oct 01 '19 at 13:00

1 Answers1

2

Here is a featured implementation for your problem.

First save and set permissions to this bash script for your user.
You will need to call it from your .qmail file:

extract-pdf-attachments.sh

#!/usr/bin/env bash

# This script process mail message attachments from stdin MIME message
# Extract all PDF files attachments
# and return the MIME message to stdout for further processing

# Ensure all locale settings are set to C, to prevent
# reformime from failing MIME headers decode with
# [unknown character set: ANSI_X3.4-1968]
# See: https://bugs.gentoo.org/304093
export LC_ALL=C LANG=C LANGUAGE=C

# Setting the destination path for saved attachments
attachements='/home/users/name/home'

trap 'rm -f -- "$mailmessage"' EXIT # Purge temporary mail message

# Create a temporary message file
mailmessage="$(mktemp)"

# Save stdin message to tempfile
cat > "$mailmessage"

# Iterate all MIME sections from the message
while read -r mime_section; do

  # Get all section info headers
  section_info="$(reformime -s "$mime_section" -i <"$mailmessage")"

  # Parse the Content-Type header
  content_type="$(grep 'content-type' <<<"$section_info" | cut -d ' ' -f 2-)"

  # Parse the Content-Name header (if available)
  content_name="$(grep 'content-name' <<<"$section_info" | cut -d ' ' -f 2-)"

  # Decode the value of the Content-Name header
  content_name="$(reformime -c UTF-8 -h "$content_name")"

  if [[ $content_type = "application/pdf" || $content_name =~ .*\.[pP][dD][fF] ]]; then
    # Attachment is a PDF
    if [ -z "$content_name" ]; then
      # The attachment has no name, so create a random name
      content_name="$(mktemp --dry-run unnamed_XXXXXXXX.pdf)"
    fi
    # Prepend the date to the attachment filename
    filename="$(date +%Y%m%d)_$content_name"

    # Save the attachment to a file
    reformime -s "$mime_section" -e <"$mailmessage" >"$attachements/$filename"
  fi

done < <(reformime < "$mailmessage") # reformime list all mime sections

cat <"$mailmessage" # Re-inject the message to stdout for further processing

Then in you .qmail:

#------------------------------------------------------------
| condredirect pdf-junkmail headermatch 'X-Spam-Status: Yes'
| bash /path/to/extract-pdf-attachments.sh | condredirect done true
# Forward not set
# Vacation Message not set
./Maildir/
Apojoost
  • 127
  • 10
Léa Gris
  • 17,497
  • 4
  • 32
  • 41
  • All the attachements are named YYYYMMDD_unnamed_XXXXXXXX.pdf. If I try to comprehend the above code I would think that the names should be YYYYMMDD_named.pdf. What goes wrong? – Apojoost Oct 22 '19 at 20:27
  • I cannot move it to the mailbox named "done". The mailbox "done" is a maildir (mailbox format); so ./Maildir/.done/ – Apojoost Oct 22 '19 at 21:27
  • If the attachment file has no `content_name` in the MIME section, then apply the name `YYYYMMDD_unnamed_.pdf`, otherwise name it with `YYYYMMDD_content_name`. For the `done` mailbox, maybe I have no qmail at hand, use `.done` or full filesystem path, I am really not certain of the syntax to use here. – Léa Gris Oct 23 '19 at 00:48
  • I don't get your answer. If I sent a mail with the attachment "hello.pdf", I get an attachment with the name "20191023_unnamed_05ckYsc5.pdf" saved. If I read the script correctly you first assign the name "hello.pd" to the string content_name but in the next line you rewrite the string content_name by feeding it with a reformime command. Am I correct? Or maybe I don't understand you. I appreciate your help very much. – Apojoost Oct 23 '19 at 20:53
  • My bad, I derped on the empty name test. I fixed my answer. Replace `if [ -n "$content_name" ];` by `if [ -z "$content_name" ];` – Léa Gris Oct 24 '19 at 13:41
  • Now I'v got the following: "20191025_[unknown character set: ANSI_X3.4-1968]". You've got a solution? – Apojoost Oct 25 '19 at 07:35
  • `ANSI_X3.4-1968` is the international registry ID of `ASCII`, most likely the error comes from `reformime` who does not recognizes the `Content-Name:` header content. First try inserting `export LC_ALL=C LANG=C LANGUAGE=C` at start of script (after the shebang). If it does not help, you may have a bad `maildrop` version, see related mail-filter maildrop bug: https://bugs.gentoo.org/304093 – Léa Gris Oct 25 '19 at 09:40
  • Inserting `export LC_ALL=C LANG=C LANGUAGE=C` doesn't make a difference. `cat Maildir/cur/1572520822.22963.server:2, | reformime -s "$mime_section" -i ` gives a readable content-name, so I think it looks like reformime can read it? Or am I mistaken? (The maildrop version is 2.5.0.) Any more suggestions? – Apojoost Oct 31 '19 at 12:12
  • Try updating maildrop. Using version `maildrop 2.9.3` here. – Léa Gris Oct 31 '19 at 16:22
  • If I try the debug the script by adding: `# DEBUG
    exec 5> debug.txt BASH_XTRACEFD="5" PS4='$LINENO: ' set -x` to the script. It seems like some thing goes wrong here: `# Decode the value of the Content-Name header content_name="$(reformime -h "$content_name")"` I don't understand this part. What are we doing here?
    – Apojoost Nov 30 '19 at 22:43
  • @Apojoost This parts processes the Content-Name header of the attachment's MIME section to get the name of the attached pdf file. – Léa Gris Dec 01 '19 at 01:38
  • If I leave out the line `content_name="$(reformime -h "$content_name")"` the script works. Is this line nescessary? Is there something wrong in this line? – Apojoost Dec 02 '19 at 22:35
  • 1
    Solved it by adding the '-c' option to refomime. Thus 'content_name="$(reformime -c UTF-8 -h "$content_name")"' source: https://sourceforge.net/p/courier/mailman/message/24972857/ – Apojoost Dec 06 '19 at 20:30
  • How can I change the subject of a message with a pdf within the script. Can I use something as: `sed 's/\(^Subject:\).*/\1 [Afgehandeld]/' "$mailmessage"`? – Apojoost May 28 '20 at 22:30
  • 1
    2021 still working! on Ubuntu, I needed to install maildrop to have the command "reformime" – AwesomeUserName Sep 08 '21 at 03:32