Check if mail was sent succesfully in bash - bash

I have this bash script that sends to my email the new IP address if it has changed running on a crontab.
SUBJ="My new IP is "
EMAIL="myemail#gmail.com"
ip1=""
ip2=""
read ip1 < ip.txt
ip2=$(wget -qO- ifconfig.me/ip)
if [ "$ip1" = "$ip2" ]
then
exit
else
echo "$ip2" > ip.txt
echo "$ip2" | mail -s "$SUBJ""$ip2" $EMAIL
exit
fi
The problem is that if for any reason the email could not been sent, the ip.text file would still change, and the next time that the script runs "$ip1" = "$ip2" would be true and never send the email.
How can I check if the mail was sent successfully?
I followed this tutorial:

If you just want to ensure that the mail program ran successfully, use
echo "$ip2" | mail -s "$SUBJ $ip2" && echo "$ip2" > ip.txt
If you actually care about the mail being successfully delivered after mail sends it to your local mail transfer agent, there's not much you can do.

Related

Sending email in telnet with bash script, unexpected token 'newline' with MAIL FROM:<>

I am trying to send an email using telnet in a bash script, I was able to do this without the bash script but wanted to make it more user friendly. I thought the newline was important for telnet to process information, but it's telling me it's producing an error.
#!/bin/bash
echo 'Enter your email'
read email
echo 'Enter your password'
read password
echo 'Enter who you want to send an email to'
read recipient
echo 'Enter your subject'
read subject
echo 'Enter your message'
read message
newPassword=$(echo -ne $password | base64)
newEmail=$(echo -ne $email | base64)
(
telnet -z ssl smtp.gmail.com 465
echo 'Sleeping: about to run HELO'
sleep 2
HELO hellogoogle
echo 'Sleeping: about to run AUTH'
sleep 2
AUTH LOGIN
echo 'Sleeping: about to enter email'
sleep 2
newEmail
echo 'Sleeping: about to enter password'
sleep 2
newPassword
echo 'Sleeping: about to run FROM'
sleep 2
MAIL FROM:<email>
echo 'Sleeping: about to run TO'
sleep 2
RCPT TO:<recipient>
echo 'Sleeping: about to run DATA'
sleep 2
DATA
echo 'Sleeping: about to enter subject'
sleep 2
Subject: subject
echo 'Sleeping: about to enter message'
sleep 2
message
.
) | telnet
I tried to do this without the parenthesis and it still did not work. Since it takes some time for telnet to open up I added sleep in between each command, along with an output letting me know what is happening.
I am trying to send an email to myself using telnet with a bash script.
You might have better luck using a heredoc which can contain variables. Here's a basic example of sending a command to webserver using netcat:
file='index.html'
cat <<EOT | nc www.example.com 80
GET /$file HTTP/1.0
EOT
I don't have telnet which is why I'm using netcat. There's a new version that supports ssl. The heredoc should also work with telnet.

unix, email attachment not being attached

I am trying to send an attachment via a script and the logic works if i run manually but not as part of the script. if I add echo, the email goes out and populates with uuencode jef20.txt jef20.txt but no attachment. any ideas?
#!/bin/bash
echo Your Username?
read user
echo FIX Session?
read session
echo what client?
read client
awk '!/35=0|35=A|35=5|35=2|35=1|closed/' /company/gate/app_phoenix/logs/fix/$session >> /home/dnash/$client.txt
uuencode $client.txt $client.txt | mailx -s "Cert Logs" "$user#company.com"
Depending on your version of mailx , you can use the -a ( "attach" ) command line switch:
mailx -a "$client.txt" -s "Cert Logs" "$user#company.com"
See Also
mailx manpage
how to send an email via mailx with enclosed file

If else in bash script for shell command

I have written a bash script that does not show any errors. However I would like to add conditional block list if success then show email success else show error message in email as shown in the code below.
scp -i id_rsa -r testuser#1.1.1.:/data1/scp ~/data/scp/files
success >> ~/data/scp/files/log.txt 2>&1
if success
then
| mail -s "Download
Successfull" abc#test.com <<< "Files Successfully Downloaded"
else
| mail -s "Error: Download Failed" abc#test.com <<< "Error File download
Failed!"
fi
Here is the working script without If else block
#!/module/for/bash
scp -i id_rsa -r test#1.1.1.1:/data1/scp ~/data/scp/files
echo success! >> ~/data/scp/files/log.txt 2>&1 | mail -s "Download
Successfull" abc#test.com <<< "Files Successfully
Downloaded" | mail -s "Error: Download Failed" abc#test.com <<<
"Error:file download Failed!"
The scp man page states: The scp utility exits 0 on success, and >0 if an error occurs.
So you can do something like:
if scp -i id_rsa -r testuser#1.1.1.:/data1/scp ~/data/scp/files
then
mail -s "Download Successful" abc#test.com <<<"Files Downloaded"
else
mail -s "Download Error" abc#test.com <<<"Download error"
fi
or
scp -i id_rsa -r testuser#1.1.1.:/data1/scp ~/data/scp/files
if [[ $? -eq 0 ]]
then
mail -s "Download Successful" abc#test.com <<<"Files Downloaded"
else
mail -s "Download Error" abc#test.com <<<"Download error"
fi
finally you may also want to look at something like storing the scp output. Use -q to have scp not print out progress meters and what not:
MYOUT=$(scp -q -i id_rsa -r testuser#1.1.1.:/data1/scp ~/data/scp/files 2>&1)
if [[ $? -eq 0 ]]
then
mail -s "Download Successful" abc#test.com <<<"$MYOUT"
else
mail -s "Download Error" abc#test.com <<<"$MYOUT"
fi
This link should clear the air. Hope it helped!
#Korthrun has already posted several ways to accomplish what I think you're trying to do; I'll take a look at what's going wrong in your current script. You seem to be confused about a couple of basic elements of shell scripting: pipes (|) and testing for command success/failure.
Pipes are used to pass the output of one command into the input of another (and possibly then chain the output of the second command into the input of a third command, etc). But when you use a pipe string like this:
echo success! >> ~/data/scp/files/log.txt 2>&1 |
mail -s "Download Successfull" abc#test.com <<< "Files Successfully Downloaded" |
mail -s "Error: Download Failed" abc#test.com <<< "Error:file download Failed!"
the pipes aren't actually doing anything. The first pipe tries to take the output of echo and feed it to the input of mail, but the >> in the echo command sends its output to a file instead, so no actual data is sent to the mail command. Which is probably good, because the <<< on the mail command tells it to ignore the regular input (from the pipe) and feed a string as input instead! Similarly, the second pipe tries to feed the output from the first mail command (there isn't any) to the last mail command, but again it's ignored due to another <<< input string. The correct way to do this is simply to remove the pipes, and run each command separately:
echo success! >> ~/data/scp/files/log.txt 2>&1
mail -s "Download Successfull" abc#test.com <<< "Files Successfully Downloaded"
mail -s "Error: Download Failed" abc#test.com <<< "Error:file download Failed!"
This is also causing a problem in the other version of your script, where you use:
if success
then
| mail -s "Download Successfull" abc#test.com <<< "Files Successfully Downloaded"
Here, there's no command before the pipe, so it doesn't make any sense at all (and you get a shell syntax error). Just remove the pipe.
Now, about success/failure testing: you seem to be using success as a command, but it isn't one. You can either use the command you want to check the success of directly as the if conditional:
if scp ...; then
echo "It worked!"
else
echo "It failed!"
fi
or use the shell variable $? which returns the exit status of the last command (success=0, failure=anything else):
scp ...
if [ $? -eq 0 ]; then
...
There's a subtlety here that's easy to miss: the thing after if is a command, but in the second form it appears to be a logical expression (testing whether $? is equal to 0). The secret is that [ is actually a command that evaluates logical expressions and then exits with success or failure depending on whether the expression was true or false. Do not mistake [ ] for some sort of parentheses or other grouping operator, that's not what's going on here!
BTW, the [[ ]] form that Korthrun used is very similar to [ ], but isn't supported by more basic shells. It does avoid some nasty syntax oddities with [ ], though, so if you're using bash it's a good way to go.
Also, note that $? gives the status of the last command executed, so it gets reset by every single command that executes. For example, this won't work:
scp ...
echo "scp's exit status was $?"
if [ $? -eq 0 ]; then # Don't do this!!!!
...because the if is then looking at the exit status of the echo command, not scp! If you need to do something like this, store the status in a variable:
scp ...
scpstatus=$?
echo "scp's exit status was $scpstatus"
if [ $scpstatus -eq 0 ]; then

Why does this bash "if" statement execute both statements

I am messing around with an rsync script to sync some stuff over to my phone. I am trying to write an if statement that decides which message I get in an email upon the commands completion. For some reason, I get both emails no matter how the command exits.
success_message=echo "Podcasts are synced." | mail -s "Your podcasts have been synced to your phone." $email_address
fail_message=echo "Your phone did not sync." | mail -s "For some reason, your podcasts did not sync today." $email_address
rsync --log-file=/home/jake/logs/rsync.log -avzu $local_directory $remote_directory
if [ $? -ne "0" ];
then
$fail_message
else
$success_message
fi
This line
success_message=echo "Podcasts are synced." | mail ...
attempts to execute a command named "Podcasts are synced." (without the quotes, but with everything in between them), and pipe its output to the "mail" command. The token "success_message=echo" causes an environment variable named "success_message" to be set in the environment of the "Podcasts are synced." command, with value "echo".
Critically, even though the thing on the left side of the pipe fails (because you don't have a program named /usr/bin/Podcasts are synced., no doubt), the mail command on the right is executed. And since there are two such lines, both commands run.
Here's how to do what you were trying to do:
send_success_message () {
echo "Podcasts are synced." |
mail -s "Your podcasts have been synced to your phone." "$1"
}
send_fail_message () {
echo "Your phone did not sync." |
mail -s "For some reason, your podcasts did not sync today." "$1"
}
if rsync --log-file=/home/jake/logs/rsync.log -avzu \
"$local_directory" "$remote_directory"
then send_success_message "$email_address"
else send_fail_message "$email_address"
fi
This line sends the message, because the first instruction ends at the pipe.
success_message=echo "Podcasts are synced." | mail -s "Your podcasts have been synced to your phone." $email_address
There's absolutely no benefit to try and put the commands into shell variables and then refer to the variables once each later. Just put the commands in the if statement:
rsync --log-file=/home/jake/logs/rsync.log -avzu $local_directory $remote_directory
if [ $? -ne "0" ];
then
echo "Podcasts are synced." | mail -s "Your podcasts have been synced to your phone." $email_address
else
echo "Your phone did not sync." | mail -s "For some reason, your podcasts did not sync today." $email_address
fi

netcat script to send a message to a marquee device

I wrote a script that uses netcat to update the marquee in my office without knowing the ip address of the device. I used fping to calculate candidateIPs.
The script works. But, I still don't know the IP address of the device. Can someone help me understand how to update the script to narrow down the IP address that updated the text on the device?
#!/bin/bash
while read p; do
echo "try $p"
echo "\x00\x00\x00\x00\x00\x01\x5A\x30\x30\x02\x41\x41\x1B\x22\x61 Test message!\x04" | nc $p 3001 &
done < candidateIPs
wait
You can log your outputs an add verbosity e.g.
#!/bin/bash
while read p; do
echo "try $p"
echo "\x00\x00\x00\x00\x00\x01\x5A\x30\x30\x02\x41\x41\x1B\x22\x61 Test message!\x04" | nc -v "$p" 3001 2>&1 | tee "$p.log" &
done < candidateIPs
wait
You can examine either the ip-specific log files after that.

Resources