Skip to content
Zeha Irawan
Twitter

Building Expense Tracker App with Gmail API

2 min read

Unfortunately, there are no apps that I can find that works automatically without manual input. Grab food does not have an API, at least not officially.

Then it comes to me, both my bank and grab food are already sending an email for each transaction.

As I have several accounts, I need to create a label & filter it, then forward it to my main account.

After that, all i need to do is to extract data that i want from the html and save it to my database.

Demo

Requirements

  • I need an app that requires as little of manual input as possible, but at the same time still allowed to make edit if needed.
  • Able to read data from multiple account, this is particularly needed if you are managing your finance with somebody else, maybe your spouse or sibling.
Create email filter Create email label

Research

First step, is try to find if somebody else already solve this problem before.

If not then, search in the Github if there is a similar projects to save hours of research.

(CubeMail)[https://github.com/KhalidLam/CubeMail]

Challenges

Solution

Challenges

await fetch(
`https://gmail.googleapis.com/gmail/v1/users/${YOUR_EMAIL}/messages?labelIds=${YOUR_LABEL_ID}`,
{
headers: {
Authorization: "Bearer " + token,
},
}
);

This call will returns a list of email id's that has 'grab' label, instead of the list of the actual email. This is a quite common, Hackernews API also use the same pattern. You have to make another call to each of the id's.

await fetch(
`https://gmail.googleapis.com/gmail/v1/users/${YOUR_EMAIL}/messages/${EMAIL_ID}`,
{
headers: {
Authorization: "Bearer " + santanaToken,
},
}
);

At first, I was thinking to loop through the id's list and then make a call with async await.

const [loading, setLoading] = useState(false);
async function fetchMyAPI() {
setLoading(true);
const ids = await getObject();
const res = await Promise.all(
ids?.map(async (email) => {
const res3 = await getEmail(email.id);
return res3;
})
);
setEmailData(res);
setLoading(false);
}
useEffect(() => {
if (user) {
fetchMyAPI();
}
}, [user]);