I’ve copied the code below that I’m trying to work with to transform emails with specific subject into another format. The trick is I need to accept multiple types of attachments but transform them into pdf & make it so that the documents get split up into multiple documents if larger then 5 pages (as documents are being sent out as faxes). I keep running into 405 errors with api2pdf calls but can’t seem to figure out what I am missing. Any assistance would be greatly appreciated !!
Code:
// Global constants
const ERRORNOTIFICATIONEMAIL = '[email protected]';
const FIXEDDESTINATIONEMAIL = '[email protected]';
const EMAIL_DOMAIN = 'Domain';
const MY_LABEL = 'Processed';
const ERROR_LABEL = 'Error Processing';
const ENABLE_PDF_SPLITTING = true;
const API2PDF_KEY = ''; // Your confirmed valid Api2Pdf API key
const PAGE_LIMIT = 5;
/**
* Main function to forward emails with processed attachments.
*/
function forwardMail() {
const threadsWithAttachments = [];
const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
const formattedDate = Utilities.formatDate(oneWeekAgo, Session.getScriptTimeZone(), 'yyyy/MM/dd');
try {
const searchQuery = `subject:"@${EMAIL_DOMAIN}" -label:"Processed" -label:"Error Processing" after:${formattedDate}`;
Logger.log(`Search query: ${searchQuery}`);
const threads = GmailApp.search(searchQuery);
Logger.log(`Found ${threads.length} threads matching query.`);
for (const thread of threads) {
const messages = thread.getMessages();
let hasError = false;
for (const message of messages) {
const subject = message.getSubject();
const senderEmail = message.getFrom();
const threadId = thread.getId();
const labels = thread.getLabels();
const isProcessed = labels.some(label => label.getName() === MY_LABEL || label.getName() === ERROR_LABEL);
Logger.log(`Checking thread: Subject="${subject}", Sender="${senderEmail}", ThreadID="${threadId}", Processed=${isProcessed}`);
if (!isProcessed) {
Logger.log(`Processing thread: Subject="${subject}", Sender="${senderEmail}", ThreadID="${threadId}`);
try {
const attachments = message.getAttachments();
Logger.log(`Attachments found: ${attachments.length}`);
attachments.forEach(att => Logger.log(`Attachment: ${att.getName()}, Type: ${att.getContentType()}`));
const splitAttachments = attachments
.map(attachment => transformAndSplitAttachment(attachment, thread))
.flat()
.filter(att => att !== null);
Logger.log(`Processed split attachments: ${splitAttachments.length}`);
if (splitAttachments.length > 0) {
splitAttachments.forEach(splitAttachment => {
const newSubject = transformSubject(subject);
Logger.log(`Sending email with attachment: ${splitAttachment.getName()}`);
sendEmailWithAttachments(newSubject, [splitAttachment], subject, senderEmail, threadId);
});
threadsWithAttachments.push(thread);
} else {
Logger.log('No valid split attachments to forward.');
}
} catch (error) {
Logger.log(`Error processing thread: ${error.message}`);
sendErrorNotification('Error processing thread', error.message);
hasError = true;
}
}
}
if (hasError) {
addErrorLabel(thread);
}
}
if (threadsWithAttachments.length > 0) {
addProcessedLabel(threadsWithAttachments);
Logger.log(`Processed label added to ${threadsWithAttachments.length} threads.`);
} else {
Logger.log('No threads found with attachments.');
}
} catch (error) {
Logger.log(`Error in forwardMail: ${error.message}`);
sendErrorNotification('Error in forwardMail', error.message);
}
}
/**
* Transforms and splits attachment if necessary.
*/
function transformAndSplitAttachment(attachment, thread) {
try {
const originalBlob = attachment.copyBlob();
const sanitizedFileName = attachment.getName().replace(/[^a-zA-Z0-9]/g, '_');
if (originalBlob.getContentType() === MimeType.PDF) {
Logger.log(`Processing PDF directly: ${sanitizedFileName}`);
const pageCount = getPageCountUsingGoogleDrive(originalBlob);
if (ENABLE_PDF_SPLITTING && pageCount > PAGE_LIMIT) {
const splitPdfs = splitPdfUsingApi2Pdf(originalBlob, sanitizedFileName, pageCount);
Logger.log(`Split PDFs created: ${splitPdfs.length}`);
return splitPdfs;
}
Logger.log(`PDF does not require splitting. Pages: ${pageCount}`);
return [originalBlob];
} else {
throw new Error('Attachment is not a valid PDF.');
}
} catch (error) {
Logger.log(`Error transforming and splitting attachment: ${error.message}`);
sendErrorNotification('Error transforming attachment', error.message);
addErrorLabel(thread);
return null;
}
}
/**
* Determines the number of pages in a PDF using Google Drive.
*/
function getPageCountUsingGoogleDrive(pdfBlob) {
try {
const tempFile = DriveApp.createFile(pdfBlob);
const pdfContent = tempFile.getBlob().getDataAsString();
const pages = (pdfContent.match(//Contents/g) || []).length;
Logger.log(`Detected ${pages} pages in the PDF.`);
tempFile.setTrashed(true); // Cleanup
return pages;
} catch (error) {
Logger.log(`Error getting page count: ${error.message}`);
throw new Error('Failed to determine page count.');
}
}
/**
* Splits a PDF into smaller parts using Api2Pdf.
*/
function splitPdfUsingApi2Pdf(pdfBlob, baseFileName, pageCount) {
const blobs = [];
try {
// Upload PDF to Google Drive to get a shareable URL
const pdfFile = DriveApp.createFile(pdfBlob);
const pdfUrl = pdfFile.getUrl(); // This should return a proper URL
for (let startPage = 0; startPage < pageCount; startPage += PAGE_LIMIT) {
const endPage = Math.min(startPage + PAGE_LIMIT - 1, pageCount - 1); // Updated to handle zero-based index
const payload = {
url: pdfUrl, // Use the shareable URL
start: startPage,
end: endPage,
inline: true, // Ensure the PDF is processed inline
fileName: `${baseFileName}_Pages_${startPage + 1}_to_${endPage + 1}.pdf`, // Friendly file name
};
const options = {
method: 'POST',
contentType: 'application/json',
muteHttpExceptions: true,
payload: JSON.stringify(payload),
};
// Endpoint with API key as a query parameter
const endpoint = `https://v2.api2pdf.com/pdfsharp/extract-pages?apikey=${API2PDF_KEY}`;
Logger.log(`Sending request to: ${endpoint}`);
const response = UrlFetchApp.fetch(endpoint, options);
const jsonResponse = JSON.parse(response.getContentText() || '{}');
Logger.log(`Api2Pdf Response Code: ${response.getResponseCode()}`);
Logger.log(`Api2Pdf Response Body: ${JSON.stringify(jsonResponse, null, 2)}`);
if (jsonResponse.Success && jsonResponse.FileUrl) {
const blob = UrlFetchApp.fetch(jsonResponse.FileUrl).getBlob();
blob.setName(`${baseFileName}_Pages_${startPage + 1}_to_${endPage + 1}.pdf`);
blobs.push(blob);
} else {
throw new Error(`Api2Pdf error: ${jsonResponse.Error || 'Unknown error'}`);
}
}
} catch (error) {
Logger.log(`Error splitting PDF using Api2Pdf: ${error.message}`);
sendErrorNotification('Error splitting PDF using Api2Pdf', error.message);
return [];
}
return blobs;
}
/**
* Sends error notifications.
*/
function sendErrorNotification(subject, body) {
GmailApp.sendEmail(ERRORNOTIFICATIONEMAIL, `ERROR: ${subject}`, body);
}
/**
* Adds a "Processed" label to threads.
*/
function addProcessedLabel(threads) {
const label = GmailApp.createLabel(MY_LABEL);
threads.forEach(thread => thread.addLabel(label));
}
/**
* Adds an "Error Processing" label to threads.
*/
function addErrorLabel(thread) {
const label = GmailApp.createLabel(ERROR_LABEL);
thread.addLabel(label);
}
/**
* Sends an email with attachments.
*/
function sendEmailWithAttachments(subject, attachments, originalSubject, senderEmail, threadId) {
GmailApp.sendEmail(FIXEDDESTINATIONEMAIL, subject, `Processed email from ${senderEmail} (Thread ID: ${threadId})nnOriginal Subject: ${originalSubject}`, {
attachments: attachments,
});
}
Trying to use api2pdf api to split pdf attachments into multiple files. Tried a lot of variations but not really sure what I am missing. Latest error code is 422