0

I have the following script that i put togheter from the web, to send emails from terminal trough gmail.

#!/bin/bash

#sendGmail "FROM" "TO" "SUBJECT" "BODY" "ATTACHMENTS (optional)"
FROM=$1
TO=$2
SUBJECT=$3
BODY=$4

# Function to check if entered file names are really files
function check_files()
{
output_files=""
for file in $1; do
    if [ -s $file ]; then
        output_files="${output_files}${file} "
    fi
done
echo $output_files
}

if [ "$FROM" == "" ]; then
    FROM="default@gmail.com"
else    
     if [[ "$FROM" =~ "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$" ]]; then
        echo error in FROM
        exit
    fi
fi

if [[ "$TO" =~ "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$" ]]; then
    echo error in TO
    exit
fi

if [ -z "$5" ]; then
    echo $BODY | mail -r $FROM -s $SUBJECT $TO
else
    ATT=$5
    ATTACHMENTS=""
    attachments=$(check_files "$ATT")
    for attachment in $attachments; do
        ATTACHMENTS="$ATTACHMENTS $attachment"
    done
    echo $ATTACHMENTS

    echo $BODY | mail -r $FROM -s $SUBJECT -A $ATTACHMENTS $TO
fi

echo email sent!

But when i send emails, i have the following behaviours:

  • with/without attachments: If $subject is "some random theme", then the email is sent to $TO and some@mipc.localdomain, random@mipc.localdomain and theme@ mipc.localdomain.
  • without attachments: $BODY is in the email body
  • with attachments: email body is empty

EDIT: thanks to @ilkkachu, first issue was fixed, new code:

#!/bin/bash

#sendGmail "FROM" "TO" "SUBJECT" "BODY" "ATTACHMENTS (optional)"
FROM=$1
TO=$2
SUBJECT=$3
BODY=$4

if [ "$FROM" == "" ]; then
    FROM="default@gmail.com"
else    
     if [[ "$FROM" =~ "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$" ]]; then
        echo error in FROM
        exit
    fi
fi

if [[ "$TO" =~ "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$" ]]; then
    echo error in TO
    exit
fi

if [ -z "$5" ]; then
    echo "$BODY" | mail -r "$FROM" -s "$SUBJECT" "$TO"
else
    ATT=$5
    ATTACHMENTS=""
    for attachment in $ATT; do
        if [ -f $attachment ]; then
            ATTACHMENTS="$ATTACHMENTS-A $attachment "
        else
            echo something wrong with $attachment, therefore not attached
        fi  
    done

    echo "$BODY" | mail -r "$FROM" -s "$SUBJECT" $ATTACHMENTS "$TO"
fi

echo email sent!

1 Answers1

2

That's because of word splitting. If SUBJECT contains some random theme, then mail -s $SUBJECT is the same as mail -s some random theme. The contents of $subject is split to words on the whitespace. You need to use quotes: mail -s "$SUBJECT".

About the attachments, you probably need to add the -A option for each file, so instead of -A file1 file2, you may need -A file1 -A file2. If your filenames don't contain whitespace, you could do that by adding the -A in ATTACHMENTS for each filename, e.g.: ATTACHMENTS="$ATTACHMENTS -A $attachment" and then use $ATTACHMENTS by itself on the mail command (you don't want quotes here, since the option and file names need to be split).

The proper way would of course be to use an array to hold the command line arguments, but your for loop already causes word splitting on the attachments, so an array wouldn't help.

So:

for f in files... ; do
    ATTACHMENTS="-A $f"
done
echo "$BODY" | mail -r "$FROM" -s "$SUBJECT" $ATTACHMENTS "$TO"

I'll also assume you've checked your mail uses -A to take attachments. There are a number of versions of mail, and the ones I found don't know that option. E.g. the one whose man page is on die.net takes -a for attachments, and uses -A for something else. So, you may want to double check that if it doesn't work.

ilkkachu
  • 138,973
  • thanks, i'll test it out and let you know. And yes, i checked and in my case the correct option is -A – kurokirasama Jul 03 '18 at 20:16
  • @kurokirasama, Though I have to say I can't see why adding the attachment would break the message body. Issues with $SUBJECT or $ATTACHMENTS should just appear as new recipients for message, just as you saw. You may need to check that the echo $BODY in the attachment branch doesn't have any weird typos. The shell won't warn if you've written echo $BOD, or some other less visible mistake. – ilkkachu Jul 03 '18 at 20:38
  • Hello, with your response i could fix the problem with the subject. But even after adding -A to the for loop, i still get problems with sending attachments. However, i realice that it was the function check_files (i don't know why). I added its functionality to the for loop and now it works great, – kurokirasama Jul 03 '18 at 23:41
  • @kurokirasama, hmm, there doesn't seem to be anything obviously wrong about the function, but I haven't had enough coffee to look at it too closely. Anyway, you might want to use [ -f "$file" ] instead of [ -s "$file" ], -f tests for regular files, -s just for non-zero size, which directories usually also have... Or maybe even [ -f "$file" ] && [ -s "$file" ] to test for both. – ilkkachu Jul 04 '18 at 09:04
  • And yeah, usually you'd want to quote all variable expansions (unless you explicitly want word splitting, like in the for attachment in $ATT; do. See: Why does my shell script choke on whitespace or other special characters? and When is double-quoting necessary? – ilkkachu Jul 04 '18 at 09:05
  • i just tried the script again with attachments and it doesn't add the body.... any ideas? – kurokirasama Jul 07 '18 at 01:52
  • @kurokirasama, I tested that quickly with GNU mailutils, echo "hello there" | mail.mailutils -A foo.txt -s 'test test' $emailaddress seems to work and I can't see anything obviously wrong in your script. Try if it works when running manually, and double-check the script for typos or any weird/invisible characters – ilkkachu Jul 07 '18 at 10:37