#!/usr/bin/env sh # # by Siddharth Dushantha 2020 # # Dependencies: jq, curl, w3m # VERSION=1.1.7 # By default 'tmpmail' uses 'w3m' as it's web browser to render # the HTML of the email BROWSER="w3m" # If the value is set to 'true' tmpmail will convert the HTML email # to raw text and send that to stdout RAW_TEXT=false # Everything related to 'tmpmail' will be stored in /tmp/tmpmail # so that the old emails and email addresses get cleared after # restarting the computer TMPMAIL_DIR="/tmp/tmpmail" # TMPMAIL_EMAIL_ADDRESS is where we store the temporary email address # that gets generated. This prevents the user from providing # the email address everytime they run tmpmail TMPMAIL_EMAIL_ADDRESS="$TMPMAIL_DIR/email_address" # tmpmail.html is where the email gets stored. # Even though the file ends with a .html extension, the raw text version of # the email will also be stored in this file so that w3m and other browsers # are able to open this file TMPMAIL_HTML_EMAIL="$TMPMAIL_DIR/tmpmail.html" # Default 1secmail API URL TMPMAIL_API_URL="https://www.1secmail.com/api/v1/" usage() { # Using 'cat << EOF' we can easily output a multiline text. This is much # better than using 'echo' for each line or using '\n' to create a new line. cat <"$TMPMAIL_EMAIL_ADDRESS" # If this function was called because the user wanted to generate a new # email address, show them the email address [ "$EXTERNALLY" = true ] && cat "$TMPMAIL_EMAIL_ADDRESS" && printf "\n" } get_email_address() { # This function is only called once and that is when this script # get executed. The output of this function gets stored in $EMAIL_ADDRESS # # If the file that contains the email address is empty, # that means we do not have an email address, so generate one. [ ! -s "$TMPMAIL_EMAIL_ADDRESS" ] && generate_email_address # Output the email address by getting the first line of $TMPMAIL_EMAIL head -n 1 "$TMPMAIL_EMAIL_ADDRESS" } list_emails() { # List all the received emails in a nicely formatted order # # Fetch the email data using 1secmail's API DATA=$(curl -sL "$TMPMAIL_API_URL?action=getMessages&login=$USERNAME&domain=$DOMAIN") # Using 'jq' we get the length of the JSON data. From this we can determine whether or not # the email address has gotten any emails DATA_LENGTH=$(printf %s "$DATA" | jq length) # We are showing what email address is currently being used # in case the user has forgotten what the email address was. printf "[ Inbox for %s ]\n\n" "$EMAIL_ADDRESS" # If the length of the data we got is 0, that means the email address # has not received any emails yet. [ "$DATA_LENGTH" -eq 0 ] && echo "No new mail" && exit # This is where we store all of our emails, which is then # displayed using 'column' INBOX="" # Go through each mail that has been received index=1 while [ $index -le "${DATA_LENGTH}" ]; do # Since arrays in JSON data start at 0, we must subtract # the value of $index by 1 so that we dont miss one of the # emails in the array MAIL_DATA=$(printf %s "$DATA" | jq -r ".[$index-1]") ID=$(printf %s "$MAIL_DATA" | jq -r ".id") FROM=$(printf %s "$MAIL_DATA" | jq -r ".from") SUBJECT=$(printf %s "$MAIL_DATA" | jq -r ".subject") # The '||' are used as a divideder for 'column'. 'column' will use this divider as # a point of reference to create the division. By default 'column' uses a blank space # but that would not work in our case as the email subject could have multiple white spaces # and 'column' would split the words that are seperated by white space, in different columns. INBOX="$INBOX$ID ||$FROM ||$SUBJECT\n" index=$((index + 1)) done # Show the emails cleanly printf "%b" "$INBOX" | column -t -s "||" } randomize() { # We could use 'shuf' and 'sort -R' but they are not a part of POSIX awk 'BEGIN {srand();} {print rand(), $0}' | \ sort -n -k1 | cut -d' ' -f2 } view_email() { # View an email by providing it's ID # # The first argument provided to this function will be the ID of the email # that has been received EMAIL_ID="$1" DATA=$(curl -sL "${TMPMAIL_API_URL}?action=readMessage&login=$USERNAME&domain=$DOMAIN&id=$EMAIL_ID") # After the data is retrieved using the API, we have to check if we got any emails. # Luckly 1secmail's API is not complicated and returns 'Message not found' as plain text # if our email address as not received any emails. # If we received the error message from the API just quit because there is nothing to do [ "$DATA" = "Message not found" ] && print_error "Message not found" # We pass the $DATA to 'jq' which extracts the values FROM=$(printf %s "$DATA" | jq -r ".from") SUBJECT=$(printf %s "$DATA" | jq -r ".subject") HTML_BODY=$(printf %s "$DATA" | jq -r ".htmlBody") ATTACHMENTS=$(printf %s "$DATA" | jq -r ".attachments | length") # If you get an email that is in pure text, the .htmlBody field will be empty and # we will need to get the content from .textBody instead [ -z "$HTML_BODY" ] && HTML_BODY="
$(printf %s "$DATA" | jq -r ".textBody")
" # Create the HTML with all the information that is relevant and then # assigning that HTML to the variable HTML_MAIL. This is the best method # to create a multiline variable HTML_MAIL=$(cat <To: $EMAIL_ADDRESS From: $FROM Subject: $SUBJECT $HTML_BODY EOF ) if [ ! "$ATTACHMENTS" = "0" ]; then HTML_MAIL="$HTML_MAIL
[Attachments]
" index=1 while [ "$index" -le "$ATTACHMENTS" ]; do FILENAME=$(printf %s "$DATA" | jq -r ".attachments | .[$index-1] | .filename") LINK="$TMPMAIL_API_URL?action=download&login=$USERNAME&domain=$DOMAIN&id=$EMAIL_ID&file=$FILENAME" HTML_LINK="$FILENAME
" if [ "$RAW_TEXT" = true ]; then # The actual url is way too long and does not look so nice in STDOUT. # Therefore we will shortening it using is.gd so that it looks nicer. LINK=$(curl -s -F"url=$LINK" "https://is.gd/create.php?format=simple") HTML_MAIL="$HTML_MAIL$LINK [$FILENAME]
" else HTML_MAIL="$HTML_MAIL$HTML_LINK" fi index=$((index + 1)) done fi # Save the $HTML_MAIL into $TMPMAIL_HTML_EMAIL printf %s "$HTML_MAIL" >"$TMPMAIL_HTML_EMAIL" # If the '--text' flag is used, then use 'w3m' to convert the HTML of # the email to pure text by removing all the HTML tags [ "$RAW_TEXT" = true ] && w3m -dump "$TMPMAIL_HTML_EMAIL" && exit # Open up the HTML file using $BROWSER. By default, # this will be 'w3m'. $BROWSER "$TMPMAIL_HTML_EMAIL" } view_recent_email() { # View the most recent email. # # This is done by listing all the received email like you # normally see on the terminal when running 'tmpmail'. # We then grab the ID of the most recent # email, which the first line. MAIL_ID=$(list_emails | head -3 | tail -1 | cut -d' ' -f 1) view_email "$MAIL_ID" } print_error() { # Print error message # # The first argument provided to this function will be the error message. # Script will exit after printing the error message. printf "%s\n" "Error: $1" >&2 exit 1 } main() { # Iterate of the array of dependencies and check if the user has them installed. # We are checking if $BROWSER is installed instead of checking for 'w3m'. By doing # this, it allows the user to not have to install 'w3m' if they are using another # browser to view the HTML for dependency in jq $BROWSER curl; do if ! command -v "$dependency" >/dev/null 2>&1; then print_error "Could not find '$dependency', is it installed?" fi done # Create the $TMPMAIL_DIR directory and dont throw any errors # if it already exists mkdir -p "$TMPMAIL_DIR" # Get the email address and save the value to the EMAIL_ADDRESS variable EMAIL_ADDRESS="$(get_email_address)" # ${VAR#PATTERN} Removes shortest match of pattern from start of a string. # In this case, it takes the EMAIL_ADDRESS and removed everything after # the '@' symbol which gives us the username. USERNAME=${EMAIL_ADDRESS%@*} # ${VAR%PATTERN} Remove shortest match of pattern from end of a string. # In this case, it takes the EMAIL_ADDRESS and removes everything until the # period '.' which gives us the domain DOMAIN=${EMAIL_ADDRESS#*@} # If no arguments are provided just the emails [ $# -eq 0 ] && list_emails && exit while [ "$1" ]; do case "$1" in --help | -h) usage && exit ;; --generate | -g) generate_email_address true "$2" && exit ;; --browser | -b) BROWSER="$2" ;; --text | -t) RAW_TEXT=true ;; --version) echo "$VERSION" && exit ;; --recent | -r) view_recent_email && exit ;; *[0-9]*) # If the user provides number as an argument, # assume its the ID of an email and try getting # the email that belongs to the ID view_email "$1" && exit ;; -*) print_error "option '$1' does not exist" ;; esac shift done } main "$@"