Question

Custom Gmail App Authentication Issue

  • 5 February 2024
  • 0 replies
  • 36 views

Userlevel 6
Badge +8

I’ve built a custom (private) Gmail integration for a client in the Zapier Platform to use some API actions not included in the standard Gmail integration - checking whether a label exists for a given year, creating it if it doesn’t, adding a child label to the year (to represent a particular event), and then creating a filter so that emails from a given client are always assigned that label.

Everything appears to be set up correctly.

OAuth test authentication in Zapier platform works like a charm:

 

Testing the action’s API request (which does all of the above in one action step) works as expected:

 

Testing the action in the Zapier editor works as expected:

 

But for some reason, live runs fail with the following error message:

 

 

Any ideas on what’s going on here? For those who would like to see it, I’ve included the code for the step below:

// Function to get a list of all existing labels from Gmail account
const getLabels = () => {
const options = {
url: `https://gmail.googleapis.com/gmail/v1/users/me/labels`,
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${bundle.authData.access_token}`
}
};

return z.request(options).then((response) => {
response.throwForStatus();
return response.json;
});
};

// Function to create a new label
const createLabel = (labelName) => {
const options = {
url: `https://gmail.googleapis.com/gmail/v1/users/me/labels`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${bundle.authData.access_token}`
},
body: {
"name": labelName
}
};

return z.request(options).then((response) => {
response.throwForStatus();
return response.json;
});
}

// Helper function to format date as M.DD.YY
const formatDateMDDYY = (date) => {
const eventMonth = (date.getMonth() + 1).toString();
const eventDay = date.getDate().toString().padStart(2, '0');
const eventYear = date.getFullYear().toString().slice(-2);
return `${eventMonth}.${eventDay}.${eventYear}`;
};

// Function to ensure a label exists for the given year and to create a child event label
const ensureYearLabelAndCreateEventLabel = (labels) => {
const eventDate = new Date(bundle.inputData.event_date);
const year = eventDate.getFullYear();
const yearLabel = `Clients/${year}`;

const existingLabel = labels.labels.find(label => label.name === yearLabel);

const labelPromise = existingLabel ? Promise.resolve(existingLabel) : createLabel(yearLabel);

return labelPromise.then(targetLabel => {
const formattedDate = formatDateMDDYY(eventDate);
const labelName = `${targetLabel.name}/${formattedDate} - ${bundle.inputData.event_name}`;
return createLabel(labelName);
});
}

// Function to get a list of all existing labels from Gmail account
const getFilters = () => {
const options = {
url: 'https://gmail.googleapis.com/gmail/v1/users/me/settings/filters',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${bundle.authData.access_token}`
}
};

return z.request(options).then(response => {
if (response.json) {
response.throwForStatus();
return response.json;
}
return {filter: false};
});
};

// Function to find and delete filters matching a given email address
const findAndDeleteFilter = (filters, emailAddress) => {
if (emailAddress) {
const targetFilter = filters.find(filter => {
if (!filter.criteria.from) {
return false;
}
const emailAddresses = filter.criteria.from.split(/\sOR\s/i);
return emailAddresses.includes(emailAddress);
});

if (!targetFilter) {
return;
}

const options = {
url: `https://gmail.googleapis.com/gmail/v1/users/me/settings/filters/${targetFilter.id}`,
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${bundle.authData.access_token}`
}
}

return z.request(options);
}
}

// Function to check whether any filters exist for either the primary or secondary email address and deletes theme
const findAndDeleteFilters = async (filterObject) => {
if (filterObject.filter) {
const filters = filterObject.filter;
await Promise.all([
findAndDeleteFilter(filters, bundle.inputData.primary_email),
findAndDeleteFilter(filters, bundle.inputData.secondary_email)
]);
return { message: "Filters deleted." };
}
return { message: "No filters were found." };
};

// Function to create a new filter and assign it to given label
const createFilter = (label) => {
let primary = bundle.inputData.primary_email;
let secondary = bundle.inputData.secondary_email;
let emailAddresses = primary;

if (primary && secondary) {
emailAddresses = `${primary} OR ${secondary}`;
}

const options = {
url: `https://gmail.googleapis.com/gmail/v1/users/me/settings/filters`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${bundle.authData.access_token}`
},
body: {
"action": {
"addLabelIds": [label.id]
},
"criteria": {
"from": emailAddresses
}
}
};

return z.request(options).then((response) => {
response.throwForStatus();
return response.json;
});
}

// Main execution flow
return getLabels()
.then(ensureYearLabelAndCreateEventLabel)
.then(createdLabel => getFilters().then(filters => ({filters, createdLabel})))
.then(({filters, createdLabel}) => findAndDeleteFilters(filters).then(() => createdLabel))
.then(createFilter)
.catch(error => {
// Log more detailed information about the error
console.error("Error Details:", error);
return {
message: "There was an error.",
errorDetails: error.message
}
});

 


0 replies

Be the first to reply!

Reply