Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, folderId, messageId } from '../common/props';
|
||||
|
||||
export const archiveEmailAction = createAction({
|
||||
auth: zohoMailAuth,
|
||||
name: 'archive_email',
|
||||
displayName: 'Archive Email',
|
||||
description: 'Archives an email.',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
folderId: folderId({ displayName: 'Folder', required: true }),
|
||||
messageId: messageId({
|
||||
displayName: 'Message ID',
|
||||
description: 'The ID of the email message to archive.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { accountId, messageId } = context.propsValue;
|
||||
|
||||
const response = await zohoMailApiCall({
|
||||
auth: context.auth,
|
||||
method: HttpMethod.PUT,
|
||||
resourceUri: `/accounts/${accountId}/updatemessage`,
|
||||
body: {
|
||||
mode: 'archiveMails',
|
||||
messageId: [messageId],
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { convertAttachment, parseStream, zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, folderId, messageId } from '../common/props';
|
||||
|
||||
export const getEmailDetailsAction = createAction({
|
||||
auth: zohoMailAuth,
|
||||
name: 'get_email_details',
|
||||
displayName: 'Get Email Details',
|
||||
description: 'Retrieves full content and metadata of a specific email.',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
folderId: folderId({ displayName: 'Folder', required: true }),
|
||||
messageId: messageId({
|
||||
displayName: 'Message ID',
|
||||
description: 'The ID of the email message to retrieve.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { accountId, messageId } = context.propsValue;
|
||||
|
||||
const response = await zohoMailApiCall<{ data: { content: string; messageId: string } }>({
|
||||
auth: context.auth,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/accounts/${accountId}/messages/${messageId}/originalmessage`,
|
||||
});
|
||||
|
||||
const parsedMailResponse = await parseStream(response.data.content);
|
||||
|
||||
return {
|
||||
...parsedMailResponse,
|
||||
attachments: await convertAttachment(parsedMailResponse.attachments, context.files),
|
||||
id: response.data.messageId,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, folderId, messageId } from '../common/props';
|
||||
|
||||
export const markEmailAsReadAction = createAction({
|
||||
auth: zohoMailAuth,
|
||||
name: 'mark_email_as_read',
|
||||
displayName: 'Mark Email as Read',
|
||||
description: 'Marks an email as read.',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
folderId: folderId({ displayName: 'Folder', required: true }),
|
||||
messageId: messageId({
|
||||
displayName: 'Message ID',
|
||||
description: 'The ID of the email message to mark as read.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { accountId, messageId } = context.propsValue;
|
||||
|
||||
const response = await zohoMailApiCall({
|
||||
auth: context.auth,
|
||||
method: HttpMethod.PUT,
|
||||
resourceUri: `/accounts/${accountId}/updatemessage`,
|
||||
body: {
|
||||
mode: 'markAsRead',
|
||||
messageId: [messageId],
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, folderId, messageId } from '../common/props';
|
||||
|
||||
export const markEmailAsUnreadAction = createAction({
|
||||
auth: zohoMailAuth,
|
||||
name: 'mark_email_as_unread',
|
||||
displayName: 'Mark Emai as Unread',
|
||||
description: 'Marks an email as unread.',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
folderId: folderId({ displayName: 'Folder', required: true }),
|
||||
messageId: messageId({
|
||||
displayName: 'Message ID',
|
||||
description: 'The ID of the email message to mark as unread.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { accountId, messageId } = context.propsValue;
|
||||
|
||||
const response = await zohoMailApiCall({
|
||||
auth: context.auth,
|
||||
method: HttpMethod.PUT,
|
||||
resourceUri: `/accounts/${accountId}/updatemessage`,
|
||||
body: {
|
||||
mode: 'markAsUnread',
|
||||
messageId: [messageId],
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, folderId, messageId } from '../common/props';
|
||||
|
||||
export const moveEmailAction = createAction({
|
||||
auth: zohoMailAuth,
|
||||
name: 'move_email',
|
||||
displayName: 'Move Email to Folder',
|
||||
description: 'Moves an email to a different folder.',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
folderId: folderId({ displayName: 'Current Folder', required: true }),
|
||||
messageId: messageId({
|
||||
displayName: 'Message ID',
|
||||
description: 'The ID of the email message to move.',
|
||||
required: true,
|
||||
}),
|
||||
destfolderId: folderId({
|
||||
displayName: 'Destination Folder',
|
||||
description: 'Select the folder to move the email to.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { accountId, destfolderId, messageId, folderId } = context.propsValue;
|
||||
|
||||
const response = await zohoMailApiCall({
|
||||
auth: context.auth,
|
||||
method: HttpMethod.PUT,
|
||||
resourceUri: `/accounts/${accountId}/updatemessage`,
|
||||
|
||||
body: {
|
||||
mode: 'moveMessage',
|
||||
destfolderId: destfolderId,
|
||||
messageId: [messageId],
|
||||
isFolderSpecific: true,
|
||||
folderId: folderId,
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,136 @@
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import FormData from 'form-data';
|
||||
import { zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, fromAddress } from '../common/props';
|
||||
|
||||
export const sendEmailAction = createAction({
|
||||
auth: zohoMailAuth,
|
||||
name: 'send_email',
|
||||
displayName: 'Send Email',
|
||||
description: 'Sends an email.',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
fromAddress: fromAddress({ displayName: 'From Email Address', required: true }),
|
||||
toAddress: Property.ShortText({
|
||||
displayName: 'To Email Address',
|
||||
description: "Recipient's email address.",
|
||||
required: true,
|
||||
}),
|
||||
|
||||
subject: Property.LongText({
|
||||
displayName: 'Subject',
|
||||
required: true,
|
||||
}),
|
||||
|
||||
mailFormat: Property.StaticDropdown({
|
||||
displayName: 'Mail Format',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'HTML', value: 'html' },
|
||||
{ label: 'Plain Text', value: 'plaintext' },
|
||||
],
|
||||
},
|
||||
defaultValue: 'html',
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Content',
|
||||
description: 'HTML or plain text content of the email.',
|
||||
required: true,
|
||||
}),
|
||||
ccAddress: Property.ShortText({
|
||||
displayName: 'CC Email Address',
|
||||
description: "CC recipient's email address.",
|
||||
required: false,
|
||||
}),
|
||||
bccAddress: Property.ShortText({
|
||||
displayName: 'BCC Email Address',
|
||||
description: "BCC recipient's email address.",
|
||||
required: false,
|
||||
}),
|
||||
askReceipt: Property.StaticDropdown({
|
||||
displayName: 'Ask for Read Receipt',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Yes', value: 'yes' },
|
||||
{ label: 'No', value: 'no' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
attachment: Property.File({
|
||||
displayName: 'Attachment',
|
||||
required: false,
|
||||
}),
|
||||
attachmentName: Property.ShortText({
|
||||
displayName: 'Attachment Name',
|
||||
description: 'In case you want to change the name of the attachment.',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const {
|
||||
accountId,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
ccAddress,
|
||||
bccAddress,
|
||||
subject,
|
||||
content,
|
||||
mailFormat,
|
||||
askReceipt,
|
||||
attachment,
|
||||
attachmentName,
|
||||
} = context.propsValue;
|
||||
|
||||
const requestBody: Record<string, unknown> = {
|
||||
fromAddress,
|
||||
toAddress,
|
||||
subject,
|
||||
content,
|
||||
mailFormat: mailFormat ?? 'html',
|
||||
};
|
||||
|
||||
if (ccAddress) requestBody['ccAddress'] = ccAddress;
|
||||
if (bccAddress) requestBody['bccAddress'] = bccAddress;
|
||||
if (askReceipt) requestBody['askReceipt'] = askReceipt;
|
||||
|
||||
if (attachment) {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append(
|
||||
'attach',
|
||||
Buffer.from(attachment.base64, 'base64'),
|
||||
attachmentName || attachment.filename,
|
||||
);
|
||||
|
||||
const location = context.auth.props?.['location'] ?? 'zoho.com';
|
||||
const baseUrl = `https://mail.${location}/api`;
|
||||
|
||||
const uploadResponse = await httpClient.sendRequest<{
|
||||
data: { storeName: string; attachmentName: string; attachmentPath: string }[];
|
||||
}>({
|
||||
url: baseUrl + `/accounts/${accountId}/messages/attachments?uploadType=multipart`,
|
||||
method: HttpMethod.POST,
|
||||
body: formData,
|
||||
headers: {
|
||||
...formData.getHeaders(),
|
||||
Authorization: `Zoho-oauthtoken ${context.auth.access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
requestBody['attachments'] = uploadResponse.body.data;
|
||||
}
|
||||
|
||||
const response = await zohoMailApiCall({
|
||||
auth: context.auth,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: `/accounts/${accountId}/messages`,
|
||||
body: requestBody,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, folderId, messageId } from '../common/props';
|
||||
|
||||
export const unarchiveEmailAction = createAction({
|
||||
auth: zohoMailAuth,
|
||||
name: 'unarchive_email',
|
||||
displayName: 'Unarchive Email',
|
||||
description: 'Unarchives an email.',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
folderId: folderId({ displayName: 'Folder', required: true }),
|
||||
messageId: messageId({
|
||||
displayName: 'Message ID',
|
||||
description: 'The ID of the email message to unarchive.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { accountId, messageId } = context.propsValue;
|
||||
|
||||
const response = await zohoMailApiCall({
|
||||
auth: context.auth,
|
||||
method: HttpMethod.PUT,
|
||||
resourceUri: `/accounts/${accountId}/updatemessage`,
|
||||
body: {
|
||||
mode: 'unArchiveMails',
|
||||
messageId: [messageId],
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { PieceAuth, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const zohoMailAuth = PieceAuth.OAuth2({
|
||||
props: {
|
||||
location: Property.StaticDropdown({
|
||||
displayName: 'Location',
|
||||
description: 'The location of your Zoho Mail account.',
|
||||
required: true,
|
||||
options: {
|
||||
options: [
|
||||
{
|
||||
label: 'zoho.eu (Europe)',
|
||||
value: 'zoho.eu',
|
||||
},
|
||||
{
|
||||
label: 'zoho.com (United States)',
|
||||
value: 'zoho.com',
|
||||
},
|
||||
{
|
||||
label: 'zoho.com.au (Australia)',
|
||||
value: 'zoho.com.au',
|
||||
},
|
||||
{
|
||||
label: 'zoho.jp (Japan)',
|
||||
value: 'zoho.jp',
|
||||
},
|
||||
{
|
||||
label: 'zoho.in (India)',
|
||||
value: 'zoho.in',
|
||||
},
|
||||
{
|
||||
label: 'zohocloud.ca (Canada)',
|
||||
value: 'zohocloud.ca',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
},
|
||||
description: 'Authentication for Zoho Desk',
|
||||
scope: [
|
||||
'ZohoMail.accounts.READ',
|
||||
'ZohoMail.messages.ALL',
|
||||
'ZohoMail.folders.ALL',
|
||||
'ZohoMail.organization.accounts.READ',
|
||||
],
|
||||
authUrl: 'https://accounts.{location}/oauth/v2/auth',
|
||||
tokenUrl: 'https://accounts.{location}/oauth/v2/token',
|
||||
required: true,
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
HttpMessageBody,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
QueryParams,
|
||||
httpClient,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { FilesService, PiecePropValueSchema } from '@activepieces/pieces-framework';
|
||||
import { Attachment, ParsedMail, simpleParser } from 'mailparser';
|
||||
import { zohoMailAuth } from './auth';
|
||||
|
||||
export type ZohoMailApiCallParams = {
|
||||
auth: PiecePropValueSchema<typeof zohoMailAuth>;
|
||||
method: HttpMethod;
|
||||
resourceUri: string;
|
||||
query?: Record<string, string | number | string[] | undefined>;
|
||||
body?: any;
|
||||
};
|
||||
|
||||
export async function zohoMailApiCall<T extends HttpMessageBody>({
|
||||
auth,
|
||||
method,
|
||||
resourceUri,
|
||||
query,
|
||||
body,
|
||||
}: ZohoMailApiCallParams): Promise<T> {
|
||||
const location = auth.props?.['location'] ?? 'zoho.com';
|
||||
const baseUrl = `https://mail.${location}/api`;
|
||||
const qs: QueryParams = {};
|
||||
|
||||
if (query) {
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value !== null && value !== undefined) {
|
||||
qs[key] = String(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url: baseUrl + resourceUri,
|
||||
headers: {
|
||||
Authorization: `Zoho-oauthtoken ${auth.access_token}`,
|
||||
},
|
||||
queryParams: qs,
|
||||
body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<T>(request);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
export async function parseStream(stream: string | Buffer): Promise<ParsedMail> {
|
||||
return new Promise<ParsedMail>((resolve, reject) => {
|
||||
simpleParser(stream, (err, parsed) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(parsed);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function convertAttachment(attachments: Attachment[], files: FilesService) {
|
||||
const promises = attachments.map(async (attachment) => {
|
||||
try {
|
||||
const fileName = attachment.filename ?? `attachment-${Date.now()}`;
|
||||
return {
|
||||
fileName,
|
||||
mimeType: attachment.contentType,
|
||||
size: attachment.size,
|
||||
data: await files.write({
|
||||
fileName: fileName,
|
||||
data: attachment.content,
|
||||
}),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Failed to process attachment: ${attachment.filename}`, error);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
const results = await Promise.all(promises);
|
||||
return results.filter((result) => result !== null);
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { PiecePropValueSchema, Property } from '@activepieces/pieces-framework';
|
||||
import { zohoMailApiCall } from '.';
|
||||
import { zohoMailAuth } from './auth';
|
||||
|
||||
interface DropdownParams {
|
||||
displayName: string;
|
||||
description?: string;
|
||||
required: boolean;
|
||||
}
|
||||
|
||||
export const accountId = (params: DropdownParams) =>
|
||||
Property.Dropdown({
|
||||
auth: zohoMailAuth,
|
||||
displayName: params.displayName,
|
||||
description: params.description,
|
||||
refreshers: [],
|
||||
required: params.required,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
placeholder: 'Please connect your account first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof zohoMailAuth>;
|
||||
|
||||
const response = await zohoMailApiCall<{
|
||||
data: { accountId: string; displayName: string }[];
|
||||
}>({
|
||||
auth: authValue,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/accounts',
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.map((account) => {
|
||||
return {
|
||||
label: account.displayName || account.accountId,
|
||||
value: account.accountId,
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const folderId = (params: DropdownParams) =>
|
||||
Property.Dropdown({
|
||||
auth: zohoMailAuth,
|
||||
displayName: params.displayName,
|
||||
description: params.description,
|
||||
refreshers: ['accountId'],
|
||||
required: params.required,
|
||||
options: async ({ auth, accountId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
placeholder: 'Please connect your account first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
if (!accountId) {
|
||||
return {
|
||||
placeholder: 'Please select Account first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const authValue = auth as PiecePropValueSchema<typeof zohoMailAuth>;
|
||||
|
||||
const response = await zohoMailApiCall<{
|
||||
data: { folderId: string; path: string }[];
|
||||
}>({
|
||||
auth: authValue,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/accounts/${accountId}/folders`,
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.map((folder) => {
|
||||
return {
|
||||
label: folder.path || folder.folderId,
|
||||
value: folder.folderId,
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const messageId = (params: DropdownParams) =>
|
||||
Property.Dropdown({
|
||||
auth: zohoMailAuth,
|
||||
displayName: params.displayName,
|
||||
description: params.description,
|
||||
refreshers: ['accountId', 'folderId'],
|
||||
required: params.required,
|
||||
options: async ({ auth, accountId, folderId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
placeholder: 'Please connect your account first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
if (!accountId) {
|
||||
return {
|
||||
placeholder: 'Please select Account first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
if (!folderId) {
|
||||
return {
|
||||
placeholder: 'Please select Folder first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
const authValue = auth as PiecePropValueSchema<typeof zohoMailAuth>;
|
||||
|
||||
const response = await zohoMailApiCall<{
|
||||
data: { messageId: string; subject: string }[];
|
||||
}>({
|
||||
auth: authValue,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/accounts/${accountId}/messages/view`,
|
||||
query: {
|
||||
folderId: folderId as string,
|
||||
limit: 50,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.map((message) => {
|
||||
return {
|
||||
label: message.subject,
|
||||
value: message.messageId,
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const fromAddress = (params: DropdownParams) =>
|
||||
Property.Dropdown({
|
||||
auth: zohoMailAuth,
|
||||
displayName: params.displayName,
|
||||
description: params.description,
|
||||
refreshers: ['accountId'],
|
||||
required: params.required,
|
||||
options: async ({ auth, accountId }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
placeholder: 'Please connect your account first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
if (!accountId) {
|
||||
return {
|
||||
placeholder: 'Please select Account first.',
|
||||
options: [],
|
||||
disabled: true,
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof zohoMailAuth>;
|
||||
|
||||
const response = await zohoMailApiCall<{
|
||||
data: { sendMailDetails: { fromAddress: string }[] };
|
||||
}>({
|
||||
auth: authValue,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/accounts/${accountId}`,
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.sendMailDetails.map((account) => {
|
||||
return {
|
||||
label: account.fromAddress,
|
||||
value: account.fromAddress,
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
import {
|
||||
DedupeStrategy,
|
||||
HttpMethod,
|
||||
Polling,
|
||||
QueryParams,
|
||||
pollingHelper,
|
||||
} from '@activepieces/pieces-common';
|
||||
import {
|
||||
AppConnectionValueForAuthProperty,
|
||||
PiecePropValueSchema,
|
||||
TriggerStrategy,
|
||||
createTrigger,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { zohoMailApiCall } from '../common';
|
||||
import { zohoMailAuth } from '../common/auth';
|
||||
import { accountId, folderId } from '../common/props';
|
||||
|
||||
type Props = {
|
||||
accountId?: string;
|
||||
folderId?: string;
|
||||
};
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof zohoMailAuth>, Props> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, propsValue, lastFetchEpochMS }) {
|
||||
const { accountId, folderId } = propsValue;
|
||||
|
||||
let page = 1;
|
||||
let hasMore = true;
|
||||
const allMessages = [];
|
||||
|
||||
do {
|
||||
const queryParams: QueryParams = {
|
||||
start: page.toString(),
|
||||
limit: lastFetchEpochMS === 0 ? '10' : '200',
|
||||
};
|
||||
|
||||
if (folderId) {
|
||||
queryParams['folderId'] = folderId;
|
||||
}
|
||||
|
||||
const response = await zohoMailApiCall<{ data: { receivedTime: string }[] }>({
|
||||
auth,
|
||||
resourceUri: `/accounts/${accountId}/messages/view`,
|
||||
method: HttpMethod.GET,
|
||||
query: queryParams,
|
||||
});
|
||||
|
||||
const messages = response.data || [];
|
||||
|
||||
if (messages.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const msg of messages) {
|
||||
const receivedTime = Number(msg.receivedTime);
|
||||
if (lastFetchEpochMS > 0 && receivedTime <= lastFetchEpochMS) {
|
||||
hasMore = false;
|
||||
break; // Stop processing this page
|
||||
}
|
||||
allMessages.push(msg); // Only add if it's newer
|
||||
}
|
||||
|
||||
// if it's test mode, only fetch first page
|
||||
if (lastFetchEpochMS === 0) break;
|
||||
|
||||
if (!hasMore) {
|
||||
break;
|
||||
}
|
||||
page++;
|
||||
} while (hasMore);
|
||||
|
||||
return allMessages.map((msg) => {
|
||||
return {
|
||||
epochMilliSeconds: Number(msg.receivedTime),
|
||||
data: msg,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const newEmailReceivedTrigger = createTrigger({
|
||||
auth: zohoMailAuth,
|
||||
name: 'new_email_received',
|
||||
displayName: 'New Email Received',
|
||||
description: 'Triggers when a new email is received in a specified folder (or inbox).',
|
||||
props: {
|
||||
accountId: accountId({ displayName: 'Account', required: true }),
|
||||
folderId: folderId({
|
||||
displayName: 'Folder',
|
||||
description:
|
||||
'Select the folder to watch. If empty, watches the inbox/all messages based on API default.',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
sampleData: {
|
||||
summary: 'test mail',
|
||||
sentDateInGMT: '1749273996000',
|
||||
calendarType: 0,
|
||||
subject: 'test mail',
|
||||
messageId: '1749293811021114900',
|
||||
flagid: 'flag_not_set',
|
||||
status2: '0',
|
||||
priority: '3',
|
||||
hasInline: 'false',
|
||||
toAddress: '',
|
||||
folderId: '7723149000000002014',
|
||||
ccAddress: 'Not Provided',
|
||||
hasAttachment: '0',
|
||||
size: '238',
|
||||
sender: 'john.doe@gmail.com',
|
||||
receivedTime: '1749293811018',
|
||||
fromAddress: 'john.doe@gmail.com',
|
||||
status: '0',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user