| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- #!/usr/bin/env sh
- #
- # by Siddharth Dushantha 2020
- #
- # Dependencies: jq, curl, w3m
- #
- export LC_ALL=C
- export LC_CTYPE=C
- VERSION=1.0.9
- # 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 <<EOF
- usage: tmpmail [-h] [--generate] [--browser BROWSER] [--recent] ID
- optional arguments:
- -h, --help Show this help message
- --version Print version
- -g, --generate Generate a new email address. You may aslo pass a custom username along with this flag
- -r, --recent View the most recent email
- -t, --text View the email as raw text, where all the HTML tags are removed
- -b, --browser Change the browser that is used to render the HTML of the email (default: w3m)
- EOF
- }
- has() {
- # Check if the user 'has' a command installed
- command -v "$1" >/dev/null 2>&1
- }
- generate_email_address() {
- # There are 2 ways which this function is called in this script.
- # [1] The user wants to generate a new email and runs 'tmpmail --generate'
- # [2] The user runs 'tmpmail' to check the inbox , but /tmp/tmpmail/email_address
- # is empty or nonexistant. Therefore a new email gets automatically
- # generated before showing the inbox. But of course the inbox will
- # be empty as the newly generated email address has not been
- # sent any emails.
- #
- # When the function 'generate_email_address()' is called with the arguement
- # 'true', it means that the function was called because the user
- # ran 'tmpmail --generate'.
- #
- # We need this variable so we can know whether or not we need to show the user
- # what the email was. <-- More about this can be found further down in this function.
- EXTERNALLY=${1:-false}
- # This variable lets generate_email_address know if the user has provided a custom
- # email address which they want to use
- CUSTOM=${2:-false}
- # Generate a random email address.
- # This function is called whenever the user wants to generate a new email
- # address by running 'tmpmail --generate' or when the user runs 'tmpmail'
- # but /tmp/tmpmail/email_address is empty or nonexistent.
- #
- # We create a random username by taking the first 10 lines from /dev/random
- # and delete all the characters which are *not* lower case letters from A to Z.
- # So charcters such as dashes, periods, underscore, and numbers are all deleted,
- # giving us a text which only contains lower case letters form A to Z. We then take
- # the first 10 characters, which will be the username of the email address
- #
- # shellcheck disable=SC2018
- USERNAME=$(head /dev/urandom | tr -dc a-z | cut -c1-11)
- # Valid TLDS which 1secmail provides.
- TLDS="com net org"
- # Randomly pick one of the TLDS mentiond above.
- TLD=$(printf "%b" "$TLDS" | tr " " "\n"| shuf -n 1)
- EMAIL_ADDRESS="$USERNAME@1secmail.$TLD"
- # If the user provided a custom email address then use that email address
- if [ "$CUSTOM" != false ]; then
- EMAIL_ADDRESS=$CUSTOM
- # Do a regex check to see if the email address provided by the user is a
- # valid email address
- regexp="[a-z]+@1secmail\.(com|net|org)"
- printf "%b" "$EMAIL_ADDRESS" | grep -E "$regexp" >/dev/null
- # Get the exit status of the command above
- STATUS=$?
- [ "$STATUS" -ne 0 ] \
- && print_error "Provided email is invalid. Must match $regexp"
- fi
- # Save the generated email address to the $TMPMAIL_EMAIL_ADDRESS file
- # so that it can be whenever 'tmpmail' is run
- echo "$EMAIL_ADDRESS" >"$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"
- }
- 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=1secmail.$TLD")
- # 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=$(echo "$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=""
- # This for loop goes through each mail that have been received.
- #
- # Since we need to go through all the data, we need to tell our for loop
- # to loop from 1 to X, where X is legnth of the $DATA which contains all
- # the emails.
- #
- # Normally to loop from 1 to 5, we would use shell expansion and write:
- # for index in {1..5}; do
- # do_something
- # done
- #
- # But we a minor issue. We dont know what the final number is, and we are not allowed
- # use to variables in shell expansions like this:
- # {1..$X}
- #
- # where $X is the length of the $DATA.
- #
- # To fix this issue, we can use 'seq' which will allow us to create a sequence
- # from X to Y.
- # Example:
- # $ seq 1 5
- # 1
- # 2
- # 3
- # 4
- # 5
- #
- # We can then put those results into the foor loop
- for index in $(seq 1 "$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=$(echo "$DATA" | jq -r ".[$index-1]")
- ID=$(echo "$MAIL_DATA" | jq -r ".id")
- FROM=$(echo "$MAIL_DATA" | jq -r ".from")
- SUBJECT=$(echo "$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"
- done
- # Show the emails cleanly
- printf "%b" "$INBOX" | column -t -s "||"
- }
- 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=1secmail.$TLD&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=$(echo "$DATA" | jq -r ".from")
- SUBJECT=$(echo "$DATA" | jq -r ".subject")
- HTML_BODY=$(echo "$DATA" | jq -r ".htmlBody")
- # 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="<pre>$(echo "$DATA" | jq -r ".textBody")</pre>"
- # 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 <<EOF
- <pre><b>To: </b>$EMAIL_ADDRESS
- <b>From: </b>$FROM
- <b>Subject: </b>$SUBJECT</pre>
- $HTML_BODY
- EOF
- )
- # Save the $HTML_MAIL into $TMPMAIL_HTML_EMAIL
- echo "$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
- for dependency in jq w3m curl; do
- ! has "$dependency" && print_error "Could not find '$dependency', is it installed?"
- 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 TLD
- TLD=${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 "$@"
|