Get number of unread emails from gmail

Hello,
I have a bash script that curl my emails with IMAP call just to get a single information “how many unread email are currently there”. This value is then saved to a file in my .cache directory and polybar tab then reads it and displays it. This happens about every 5-10 minutes.

Google now decided to screw me over and disabled this IMAP option. Instead it has to be accessed via some API (that I have to somehow/somewhere enable) with OAuth2 authentication. Sadly I cannot find any reasonable documentation how to correctly set it up with a practical example - all I found was some mobile app nonsence (all in a way “embed google’s library to build some javascript crap”).

I am looking for a way how to fix my script to get this simple number and save it to a file.

Normaly, I use thunderbird to manage my emails but I do not like to lauch it every time just to check if there is something new or not.
Is there some extra light alternative that could do just that number checking in the background?

Maybe this can help you.

http://bubblemail.free.fr/

Thank you for the recommendation, but how does it work without Gnome desktop?
I looked into the documentation and it looks like it is too closely connected to the rest of the Gnome stuff. I use i3wm.

Two factor / Oauth2 authentification

Some providers, like gmail, proposes two factor identification by default, forcing user to validate authorisation using a web service. Since Bubblemail doesn’t integrate a webrowser, this task have to be done elsewhere, for instance using Gnome online accounts.

Sorry, I didn’t know it was meant to be used in i3wm, it says it’s DE independent, unfortunately I didn’t know that it didn’t support Oauth2 by default because my accounts were already configured in GOA.

1 Like

It’s not a big deal. Thanks anyway.

1 Like

Maybe you can create an app password to use in your script.

1 Like

every tried birdtray ? is mayby bit buggy is just the way how u use… but schould see numbers?

I searched the AUR (imagine that!) for “mail”.

https://aur.archlinux.org/packages/kdeplasma-applets-gmailfeed

Tnak you all for reply. I will look at those options when I have some more time in the future.

Well then, thank you for not spending any of your very important time with our suggestions, which I suppose we spent our unimportant time researching for you.

4 Likes

Sorry, that was perhaps poorly phrased. You didn’t have to do any through reserch on my behalf. :wink:
I was expecting that someone in the past was aready facing a similar problem I have now but it looks like there is no simple solution that could be easily integrated into my i3wm setup along with my other email clients. I expect it would take several hours to make something work.

1 Like

That’s what Goolag does. Hardly unexpected… I know it’s difficult, I’ve been there, but look into a replacement email.

So, I looked at the mentioned options. Sadly none of them realy work for me - I cannot activate app password because my phone is not valid for 2-factor authentication and other applications doesn’t run on my i3 system (maybe because I don’t have full DE setup).

However, after several trial and error and error and error attempts I was able to get what I wanted through google API (big thanks to these videos - video1, video2 - because the most confusing part was enabling API on the google’s side).
Below is the bash script if anyone is interested.


First step is to enable API on https://console.cloud.google.com.

Most of the stuff is mentioned in the video2 above. There are only some details missing.
Create new project and go to Library to enable “Gmail API”

picture

library

Under oauth consent screen (see picture above) the required scope is “…/auth/gmail.readonly”

picture

readonly

In Credentials panel create OAuth client ID of type "web application. Then add a redirect URI to a localhost and port listed in the bash script below.
There are also client_id and client_secret that has to be provided to the bash script below.

picture

client

That should be all the necessary steps to make the below script work. First time it will ask to login into google account and as long you do not delete the token file from the cache it will be able to access gmail api without any additional login procedure.

Final bash script - click here
#!/bin/bash

client_id="*fill in your own*"
client_secret="*fill in your own*"

browser="${BROWSER:-firefox}"
port="4521"
redirect_uri="http://localhost:${port}"

cache_dir="${HOME}/.cache/mail_counter"
[[ -d "${cache_dir}" ]] || mkdir -p "${cache_dir}"
token_file="${cache_dir}/token_$1.json"


function check_dependencies(){
    local required_software=("curl" "jq" "${browser}" "netcap")

    for app in "${required_software[@]}"; do
        [[ "$(which ${app} 2>&1)" == "which:"* ]] && echo "${app}: is not installed" && exit 100
    done
}


# user has to log in and that generates authorization code
# and netcat will receive necessary code to continue
# user is prompted to close the browser
function get_authorization_code(){
    local response_type="code"
    local scope="https://www.googleapis.com/auth/gmail.readonly"
    local access_type="offline"
    local prompt="consent"

    local url="https://accounts.google.com/o/oauth2/v2/auth?client_id=${client_id}&redirect_uri=${redirect_uri}&response_type=${response_type}&scope=${scope}&access_type=${access_type}&prompt=${prompt}"

    ${browser} "${url}" &

    # extract authorization code
    local authorization_code=$( { printf 'HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n' "33"; echo -n "authorization done, close browser"; } | \
                                netcat -l -w 600 -p ${port} | grep GET)

    # check for timeout process
    [[ -z "${authorization_code}" ]] && exit 10

    # extract the code from the http message
    authorization_code="${authorization_code#*=}"
    authorization_code="${authorization_code%&*}"

    echo "${authorization_code}"
}


# save token to cache directory
# add expiration timer so the access token can be refreshed when needed
function cache_token(){
    # calculate dedline for token refresh (with 10 seconds buffer)
    local expire_time=$(( $(date "+%s") + $(jq -j '.expires_in' <<< "$1") - 10 ))

    # store stuff in files
    jq ".expire_time = ${expire_time}" <<< "$1" | (umask 0077; cat > "${token_file}")
}


# exchange authorization code for an access and refresh token
function get_access_token(){
    local authorization_code=$(get_authorization_code)
    [[ -z "${authorization_code}" ]] && exit 20

    local a_response=$(curl -s -X POST \
                            -d "code=${authorization_code}" \
                            -d "client_id=${client_id}" \
                            -d "client_secret=${client_secret}" \
                            -d "grant_type=authorization_code" \
                            -d "redirect_uri=${redirect_uri}" \
                            "https://oauth2.googleapis.com/token" )

    cache_token "${a_response}"
}


# get new access token without user login (reset timer)
function refresh_access_token(){
    local refresh_token="$(jq -j '.refresh_token' ${token_file})"
    [[ -z "${refresh_token}" ]] && exit 30

    local r_response=$(curl -s -X POST \
                            -d "client_id=${client_id}" \
                            -d "client_secret=${client_secret}" \
                            -d "grant_type=refresh_token" \
                            -d "refresh_token=${refresh_token}" \
                            "https://oauth2.googleapis.com/token" )

    r_response=$(jq ".refresh_token = \"${refresh_token}\"" <<< "${r_response}")
    cache_token "${r_response}"
}


function get_unread_emails_count(){
    # get the token in case cache entry was deleted
    [[ -f "${token_file}" ]] || get_access_token

    # refresh token if necessary
    local expire_time=$(jq -j '.expire_time' "${token_file}")
    [[ "$(date +%s)" -ge "${expire_time}" ]] && refresh_access_token

    # get (now valid) access token
    local access_token=$(jq -j '.access_token' "${token_file}")
    [[ -z "${access_token}" ]] && exit 2
    [[ "${access_token}" == "null" ]] && exit 3

    # get number of unread emails in the mailbox
    local u_response=$(curl -s -G \
                            -d 'q="is:unread"' \
                            -d 'includeSpamTrash=false' \
                            -H 'Accept: application/json' \
                            -H "Authorization: Bearer ${access_token}" \
                            "https://gmail.googleapis.com/gmail/v1/users/me/messages" )

    local unread=$(jq -j '.resultSizeEstimate' <<< "${u_response}")
    echo "${unread}"
}

check_dependencies
get_unread_emails_count
1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.