Compare commits
	
		
			7 Commits
		
	
	
		
			dependabot
			...
			AUT-948
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d9c311d045 | ||
|   | 7985a79adc | ||
|   | 7e3b5244d8 | ||
|   | 30a98746ef | ||
|   | 55785ac935 | ||
|   | b6b4ed5ad2 | ||
|   | b594a8e0f3 | 
							
								
								
									
										204
									
								
								packages/backend/src/apps/gmail/actions/create-draft/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								packages/backend/src/apps/gmail/actions/create-draft/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | |||||||
|  | import defineAction from '../../../../helpers/define-action.js'; | ||||||
|  |  | ||||||
|  | export default defineAction({ | ||||||
|  |   name: 'Create draft', | ||||||
|  |   key: 'createDraft', | ||||||
|  |   description: 'Create a new draft email message.', | ||||||
|  |   arguments: [ | ||||||
|  |     { | ||||||
|  |       label: 'Subject', | ||||||
|  |       key: 'subject', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'TOs', | ||||||
|  |       key: 'tos', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'To', | ||||||
|  |           key: 'to', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'CCs', | ||||||
|  |       key: 'ccs', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'CC', | ||||||
|  |           key: 'cc', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'BCCs', | ||||||
|  |       key: 'bccs', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'BCC', | ||||||
|  |           key: 'bcc', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'From', | ||||||
|  |       key: 'from', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: | ||||||
|  |         'Select an email address or alias from your Gmail Account. Defaults to the primary email address.', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listEmails', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'From Name', | ||||||
|  |       key: 'fromName', | ||||||
|  |       type: 'string', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Body Type', | ||||||
|  |       key: 'bodyType', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       options: [ | ||||||
|  |         { | ||||||
|  |           label: 'plain', | ||||||
|  |           value: 'plain', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           label: 'html', | ||||||
|  |           value: 'html', | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Body', | ||||||
|  |       key: 'emailBody', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Signature', | ||||||
|  |       key: 'signature', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listSignatures', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const { | ||||||
|  |       tos, | ||||||
|  |       ccs, | ||||||
|  |       bccs, | ||||||
|  |       from, | ||||||
|  |       fromName, | ||||||
|  |       subject, | ||||||
|  |       bodyType, | ||||||
|  |       emailBody, | ||||||
|  |       signature, | ||||||
|  |     } = $.step.parameters; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const allTos = tos?.map((entry) => entry.to); | ||||||
|  |     const allCcs = ccs?.map((entry) => entry.cc); | ||||||
|  |     const allBccs = bccs?.map((entry) => entry.bcc); | ||||||
|  |     const contentType = | ||||||
|  |       bodyType === 'html' | ||||||
|  |         ? 'text/html; charset="UTF-8"' | ||||||
|  |         : 'text/plain; charset="UTF-8"'; | ||||||
|  |  | ||||||
|  |     const email = | ||||||
|  |       'From: ' + | ||||||
|  |       fromName + | ||||||
|  |       ' <' + | ||||||
|  |       from + | ||||||
|  |       '>' + | ||||||
|  |       '\r\n' + | ||||||
|  |       'To: ' + | ||||||
|  |       allTos.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Cc: ' + | ||||||
|  |       allCcs.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Bcc: ' + | ||||||
|  |       allBccs.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Subject: ' + | ||||||
|  |       subject + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Content-Type: ' + | ||||||
|  |       contentType + | ||||||
|  |       '\r\n' + | ||||||
|  |       '\r\n' + | ||||||
|  |       emailBody + | ||||||
|  |       '\r\n' + | ||||||
|  |       '\r\n' + | ||||||
|  |       signature; | ||||||
|  |  | ||||||
|  |     const base64EncodedEmailBody = Buffer.from(email).toString('base64'); | ||||||
|  |  | ||||||
|  |     const body = { | ||||||
|  |       message: { | ||||||
|  |         raw: base64EncodedEmailBody, | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.post( | ||||||
|  |       `/gmail/v1/users/${userId}/drafts`, | ||||||
|  |       body | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $.setActionItem({ | ||||||
|  |       raw: data, | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
							
								
								
									
										7
									
								
								packages/backend/src/apps/gmail/actions/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								packages/backend/src/apps/gmail/actions/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | import createDraft from './create-draft/index.js'; | ||||||
|  | import replyToEmail from './reply-to-email/index.js'; | ||||||
|  | import sendEmail from './send-email/index.js'; | ||||||
|  | import sendToTrash from './send-to-trash/index.js'; | ||||||
|  | import starEmail from './star-email/index.js'; | ||||||
|  |  | ||||||
|  | export default [createDraft, replyToEmail, sendEmail, sendToTrash, starEmail]; | ||||||
							
								
								
									
										228
									
								
								packages/backend/src/apps/gmail/actions/reply-to-email/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								packages/backend/src/apps/gmail/actions/reply-to-email/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | |||||||
|  | import defineAction from '../../../../helpers/define-action.js'; | ||||||
|  |  | ||||||
|  | export default defineAction({ | ||||||
|  |   name: 'Reply to email', | ||||||
|  |   key: 'replyToEmail', | ||||||
|  |   description: 'Respond to an email.', | ||||||
|  |   arguments: [ | ||||||
|  |     { | ||||||
|  |       label: 'Thread', | ||||||
|  |       key: 'threadId', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listThreads', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'TOs', | ||||||
|  |       key: 'tos', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: 'Who will receive this email?', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'To', | ||||||
|  |           key: 'to', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'CCs', | ||||||
|  |       key: 'ccs', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: | ||||||
|  |         'Who else needs to be included in the CC field of this email?', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'CC', | ||||||
|  |           key: 'cc', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'BCCs', | ||||||
|  |       key: 'bccs', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: | ||||||
|  |         'Who else needs to be included in the BCC field of this email?', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'BCC', | ||||||
|  |           key: 'bcc', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'From', | ||||||
|  |       key: 'from', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: | ||||||
|  |         'Choose an email address or alias from your Gmail Account. This defaults to the primary email address.', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listEmails', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'From Name', | ||||||
|  |       key: 'fromName', | ||||||
|  |       type: 'string', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Reply To', | ||||||
|  |       key: 'replyTo', | ||||||
|  |       type: 'string', | ||||||
|  |       required: false, | ||||||
|  |       description: 'Specify a single reply address other than your own.', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Body Type', | ||||||
|  |       key: 'bodyType', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       options: [ | ||||||
|  |         { | ||||||
|  |           label: 'plain', | ||||||
|  |           value: 'plain', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           label: 'html', | ||||||
|  |           value: 'html', | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Body', | ||||||
|  |       key: 'emailBody', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Label', | ||||||
|  |       key: 'labelId', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listLabels', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const { | ||||||
|  |       tos, | ||||||
|  |       ccs, | ||||||
|  |       bccs, | ||||||
|  |       from, | ||||||
|  |       fromName, | ||||||
|  |       replyTo, | ||||||
|  |       threadId, | ||||||
|  |       bodyType, | ||||||
|  |       emailBody, | ||||||
|  |       labelId, | ||||||
|  |     } = $.step.parameters; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const allTos = tos?.map((entry) => entry.to); | ||||||
|  |     const allCcs = ccs?.map((entry) => entry.cc); | ||||||
|  |     const allBccs = bccs?.map((entry) => entry.bcc); | ||||||
|  |     const contentType = | ||||||
|  |       bodyType === 'html' | ||||||
|  |         ? 'text/html; charset="UTF-8"' | ||||||
|  |         : 'text/plain; charset="UTF-8"'; | ||||||
|  |  | ||||||
|  |     const email = | ||||||
|  |       'From: ' + | ||||||
|  |       fromName + | ||||||
|  |       ' <' + | ||||||
|  |       from + | ||||||
|  |       '>' + | ||||||
|  |       '\r\n' + | ||||||
|  |       'In-Reply-To: ' + | ||||||
|  |       threadId + | ||||||
|  |       '\r\n' + | ||||||
|  |       'References: ' + | ||||||
|  |       threadId + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Reply-To: ' + | ||||||
|  |       replyTo + | ||||||
|  |       '\r\n' + | ||||||
|  |       'To: ' + | ||||||
|  |       allTos.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Cc: ' + | ||||||
|  |       allCcs.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Bcc: ' + | ||||||
|  |       allBccs.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Content-Type: ' + | ||||||
|  |       contentType + | ||||||
|  |       '\r\n' + | ||||||
|  |       '\r\n' + | ||||||
|  |       emailBody; | ||||||
|  |  | ||||||
|  |     const base64EncodedEmailBody = Buffer.from(email).toString('base64'); | ||||||
|  |  | ||||||
|  |     const body = { | ||||||
|  |       threadId: threadId, | ||||||
|  |       labelIds: [labelId], | ||||||
|  |       raw: base64EncodedEmailBody, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.post( | ||||||
|  |       `/gmail/v1/users/${userId}/messages/send`, | ||||||
|  |       body | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $.setActionItem({ | ||||||
|  |       raw: data, | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
							
								
								
									
										234
									
								
								packages/backend/src/apps/gmail/actions/send-email/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								packages/backend/src/apps/gmail/actions/send-email/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,234 @@ | |||||||
|  | import defineAction from '../../../../helpers/define-action.js'; | ||||||
|  |  | ||||||
|  | export default defineAction({ | ||||||
|  |   name: 'Send email', | ||||||
|  |   key: 'sendEmail', | ||||||
|  |   description: 'Send a new email message.', | ||||||
|  |   arguments: [ | ||||||
|  |     { | ||||||
|  |       label: 'TOs', | ||||||
|  |       key: 'tos', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'To', | ||||||
|  |           key: 'to', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'CCs', | ||||||
|  |       key: 'ccs', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'CC', | ||||||
|  |           key: 'cc', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'BCCs', | ||||||
|  |       key: 'bccs', | ||||||
|  |       type: 'dynamic', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       fields: [ | ||||||
|  |         { | ||||||
|  |           label: 'BCC', | ||||||
|  |           key: 'bcc', | ||||||
|  |           type: 'string', | ||||||
|  |           required: false, | ||||||
|  |           variables: true, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'From', | ||||||
|  |       key: 'from', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: | ||||||
|  |         'Select an email address or alias from your Gmail Account. Defaults to the primary email address.', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listEmails', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'From Name', | ||||||
|  |       key: 'fromName', | ||||||
|  |       type: 'string', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Reply To', | ||||||
|  |       key: 'replyTo', | ||||||
|  |       type: 'string', | ||||||
|  |       required: false, | ||||||
|  |       description: 'Specify a single reply address other than your own.', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Subject', | ||||||
|  |       key: 'subject', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Body Type', | ||||||
|  |       key: 'bodyType', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       options: [ | ||||||
|  |         { | ||||||
|  |           label: 'plain', | ||||||
|  |           value: 'plain', | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           label: 'html', | ||||||
|  |           value: 'html', | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Body', | ||||||
|  |       key: 'emailBody', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Signature', | ||||||
|  |       key: 'signature', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listSignatures', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: 'Label', | ||||||
|  |       key: 'labelId', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listLabels', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const { | ||||||
|  |       tos, | ||||||
|  |       ccs, | ||||||
|  |       bccs, | ||||||
|  |       from, | ||||||
|  |       fromName, | ||||||
|  |       replyTo, | ||||||
|  |       subject, | ||||||
|  |       bodyType, | ||||||
|  |       emailBody, | ||||||
|  |       signature, | ||||||
|  |       labelId, | ||||||
|  |     } = $.step.parameters; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const allTos = tos?.map((entry) => entry.to); | ||||||
|  |     const allCcs = ccs?.map((entry) => entry.cc); | ||||||
|  |     const allBccs = bccs?.map((entry) => entry.bcc); | ||||||
|  |     const contentType = | ||||||
|  |       bodyType === 'html' | ||||||
|  |         ? 'text/html; charset="UTF-8"' | ||||||
|  |         : 'text/plain; charset="UTF-8"'; | ||||||
|  |  | ||||||
|  |     const email = | ||||||
|  |       'From: ' + | ||||||
|  |       fromName + | ||||||
|  |       ' <' + | ||||||
|  |       from + | ||||||
|  |       '>' + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Reply-To: ' + | ||||||
|  |       replyTo + | ||||||
|  |       '\r\n' + | ||||||
|  |       'To: ' + | ||||||
|  |       allTos.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Cc: ' + | ||||||
|  |       allCcs.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Bcc: ' + | ||||||
|  |       allBccs.join(',') + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Subject: ' + | ||||||
|  |       subject + | ||||||
|  |       '\r\n' + | ||||||
|  |       'Content-Type: ' + | ||||||
|  |       contentType + | ||||||
|  |       '\r\n' + | ||||||
|  |       '\r\n' + | ||||||
|  |       emailBody + | ||||||
|  |       '\r\n' + | ||||||
|  |       '\r\n' + | ||||||
|  |       signature; | ||||||
|  |  | ||||||
|  |     const base64EncodedEmailBody = Buffer.from(email).toString('base64'); | ||||||
|  |  | ||||||
|  |     const body = { | ||||||
|  |       labelIds: [labelId], | ||||||
|  |       raw: base64EncodedEmailBody, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.post( | ||||||
|  |       `/gmail/v1/users/${userId}/messages/send`, | ||||||
|  |       body | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $.setActionItem({ | ||||||
|  |       raw: data, | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
| @@ -0,0 +1,30 @@ | |||||||
|  | import defineAction from '../../../../helpers/define-action.js'; | ||||||
|  |  | ||||||
|  | export default defineAction({ | ||||||
|  |   name: 'Send to trash', | ||||||
|  |   key: 'sendToTrash', | ||||||
|  |   description: 'Send an existing email message to the trash.', | ||||||
|  |   arguments: [ | ||||||
|  |     { | ||||||
|  |       label: 'Message ID', | ||||||
|  |       key: 'messageId', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const { messageId } = $.step.parameters; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.post( | ||||||
|  |       `/gmail/v1/users/${userId}/messages/${messageId}/trash` | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $.setActionItem({ | ||||||
|  |       raw: data, | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
							
								
								
									
										45
									
								
								packages/backend/src/apps/gmail/actions/star-email/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								packages/backend/src/apps/gmail/actions/star-email/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | import defineAction from '../../../../helpers/define-action.js'; | ||||||
|  |  | ||||||
|  | export default defineAction({ | ||||||
|  |   name: 'Star an email', | ||||||
|  |   key: 'starEmail', | ||||||
|  |   description: 'Star an email message.', | ||||||
|  |   arguments: [ | ||||||
|  |     { | ||||||
|  |       label: 'Message ID', | ||||||
|  |       key: 'messageId', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: true, | ||||||
|  |       description: '', | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listMessages', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const { messageId } = $.step.parameters; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const body = { | ||||||
|  |       addLabelIds: ['STARRED'], | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.post( | ||||||
|  |       `/gmail/v1/users/${userId}/messages/${messageId}/modify`, | ||||||
|  |       body | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     $.setActionItem({ | ||||||
|  |       raw: data, | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
							
								
								
									
										11
									
								
								packages/backend/src/apps/gmail/assets/favicon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								packages/backend/src/apps/gmail/assets/favicon.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 49.4 512 399.42"> | ||||||
|  |   <g fill="none" fill-rule="evenodd"> | ||||||
|  |     <g fill-rule="nonzero"> | ||||||
|  |       <path fill="#4285f4" d="M34.91 448.818h81.454V251L0 163.727V413.91c0 19.287 15.622 34.91 34.91 34.91z"/> | ||||||
|  |       <path fill="#34a853" d="M395.636 448.818h81.455c19.287 0 34.909-15.622 34.909-34.909V163.727L395.636 251z"/> | ||||||
|  |       <path fill="#fbbc04" d="M395.636 99.727V251L512 163.727v-46.545c0-43.142-49.25-67.782-83.782-41.891z"/> | ||||||
|  |     </g> | ||||||
|  |     <path fill="#ea4335" d="M116.364 251V99.727L256 204.455 395.636 99.727V251L256 355.727z"/> | ||||||
|  |     <path fill="#c5221f" fill-rule="nonzero" d="M0 117.182v46.545L116.364 251V99.727L83.782 75.291C49.25 49.4 0 74.04 0 117.18z"/> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 720 B | 
							
								
								
									
										23
									
								
								packages/backend/src/apps/gmail/auth/generate-auth-url.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								packages/backend/src/apps/gmail/auth/generate-auth-url.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | import { URLSearchParams } from 'url'; | ||||||
|  | import authScope from '../common/auth-scope.js'; | ||||||
|  |  | ||||||
|  | export default async function generateAuthUrl($) { | ||||||
|  |   const oauthRedirectUrlField = $.app.auth.fields.find( | ||||||
|  |     (field) => field.key == 'oAuthRedirectUrl' | ||||||
|  |   ); | ||||||
|  |   const redirectUri = oauthRedirectUrlField.value; | ||||||
|  |   const searchParams = new URLSearchParams({ | ||||||
|  |     client_id: $.auth.data.clientId, | ||||||
|  |     redirect_uri: redirectUri, | ||||||
|  |     prompt: 'select_account', | ||||||
|  |     scope: authScope.join(' '), | ||||||
|  |     response_type: 'code', | ||||||
|  |     access_type: 'offline', | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const url = `https://accounts.google.com/o/oauth2/v2/auth?${searchParams.toString()}`; | ||||||
|  |  | ||||||
|  |   await $.auth.set({ | ||||||
|  |     url, | ||||||
|  |   }); | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								packages/backend/src/apps/gmail/auth/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								packages/backend/src/apps/gmail/auth/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | import generateAuthUrl from './generate-auth-url.js'; | ||||||
|  | import verifyCredentials from './verify-credentials.js'; | ||||||
|  | import refreshToken from './refresh-token.js'; | ||||||
|  | import isStillVerified from './is-still-verified.js'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   fields: [ | ||||||
|  |     { | ||||||
|  |       key: 'oAuthRedirectUrl', | ||||||
|  |       label: 'OAuth Redirect URL', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       readOnly: true, | ||||||
|  |       value: '{WEB_APP_URL}/app/gmail/connections/add', | ||||||
|  |       placeholder: null, | ||||||
|  |       description: | ||||||
|  |         'When asked to input a redirect URL in Google Cloud, enter the URL above.', | ||||||
|  |       clickToCopy: true, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       key: 'clientId', | ||||||
|  |       label: 'Client ID', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       readOnly: false, | ||||||
|  |       value: null, | ||||||
|  |       placeholder: null, | ||||||
|  |       description: null, | ||||||
|  |       clickToCopy: false, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       key: 'clientSecret', | ||||||
|  |       label: 'Client Secret', | ||||||
|  |       type: 'string', | ||||||
|  |       required: true, | ||||||
|  |       readOnly: false, | ||||||
|  |       value: null, | ||||||
|  |       placeholder: null, | ||||||
|  |       description: null, | ||||||
|  |       clickToCopy: false, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  |  | ||||||
|  |   generateAuthUrl, | ||||||
|  |   verifyCredentials, | ||||||
|  |   isStillVerified, | ||||||
|  |   refreshToken, | ||||||
|  | }; | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | import getCurrentUser from '../common/get-current-user.js'; | ||||||
|  |  | ||||||
|  | const isStillVerified = async ($) => { | ||||||
|  |   const currentUser = await getCurrentUser($); | ||||||
|  |   return !!currentUser.resourceName; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default isStillVerified; | ||||||
							
								
								
									
										26
									
								
								packages/backend/src/apps/gmail/auth/refresh-token.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								packages/backend/src/apps/gmail/auth/refresh-token.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | import { URLSearchParams } from 'node:url'; | ||||||
|  |  | ||||||
|  | import authScope from '../common/auth-scope.js'; | ||||||
|  |  | ||||||
|  | const refreshToken = async ($) => { | ||||||
|  |   const params = new URLSearchParams({ | ||||||
|  |     client_id: $.auth.data.clientId, | ||||||
|  |     client_secret: $.auth.data.clientSecret, | ||||||
|  |     grant_type: 'refresh_token', | ||||||
|  |     refresh_token: $.auth.data.refreshToken, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const { data } = await $.http.post( | ||||||
|  |     'https://oauth2.googleapis.com/token', | ||||||
|  |     params.toString() | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   await $.auth.set({ | ||||||
|  |     accessToken: data.access_token, | ||||||
|  |     expiresIn: data.expires_in, | ||||||
|  |     scope: authScope.join(' '), | ||||||
|  |     tokenType: data.token_type, | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default refreshToken; | ||||||
							
								
								
									
										43
									
								
								packages/backend/src/apps/gmail/auth/verify-credentials.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								packages/backend/src/apps/gmail/auth/verify-credentials.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | import getCurrentUser from '../common/get-current-user.js'; | ||||||
|  |  | ||||||
|  | const verifyCredentials = async ($) => { | ||||||
|  |   const oauthRedirectUrlField = $.app.auth.fields.find( | ||||||
|  |     (field) => field.key == 'oAuthRedirectUrl' | ||||||
|  |   ); | ||||||
|  |   const redirectUri = oauthRedirectUrlField.value; | ||||||
|  |   const { data } = await $.http.post(`https://oauth2.googleapis.com/token`, { | ||||||
|  |     client_id: $.auth.data.clientId, | ||||||
|  |     client_secret: $.auth.data.clientSecret, | ||||||
|  |     code: $.auth.data.code, | ||||||
|  |     grant_type: 'authorization_code', | ||||||
|  |     redirect_uri: redirectUri, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   await $.auth.set({ | ||||||
|  |     accessToken: data.access_token, | ||||||
|  |     tokenType: data.token_type, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const currentUser = await getCurrentUser($); | ||||||
|  |  | ||||||
|  |   const { displayName } = currentUser.names.find( | ||||||
|  |     (name) => name.metadata.primary | ||||||
|  |   ); | ||||||
|  |   const { value: email } = currentUser.emailAddresses.find( | ||||||
|  |     (emailAddress) => emailAddress.metadata.primary | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   await $.auth.set({ | ||||||
|  |     clientId: $.auth.data.clientId, | ||||||
|  |     clientSecret: $.auth.data.clientSecret, | ||||||
|  |     scope: $.auth.data.scope, | ||||||
|  |     idToken: data.id_token, | ||||||
|  |     expiresIn: data.expires_in, | ||||||
|  |     refreshToken: data.refresh_token, | ||||||
|  |     resourceName: currentUser.resourceName, | ||||||
|  |     screenName: `${displayName} - ${email}`, | ||||||
|  |     userId: email, | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default verifyCredentials; | ||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | const addAuthHeader = ($, requestConfig) => { | ||||||
|  |   if ($.auth.data?.accessToken) { | ||||||
|  |     requestConfig.headers.Authorization = `${$.auth.data.tokenType} ${$.auth.data.accessToken}`; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return requestConfig; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default addAuthHeader; | ||||||
							
								
								
									
										8
									
								
								packages/backend/src/apps/gmail/common/auth-scope.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								packages/backend/src/apps/gmail/common/auth-scope.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | const authScope = [ | ||||||
|  |   'https://www.googleapis.com/auth/gmail.compose', | ||||||
|  |   'https://www.googleapis.com/auth/gmail.modify', | ||||||
|  |   'https://www.googleapis.com/auth/userinfo.email', | ||||||
|  |   'https://www.googleapis.com/auth/userinfo.profile', | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export default authScope; | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | const getCurrentUser = async ($) => { | ||||||
|  |   const { data: currentUser } = await $.http.get( | ||||||
|  |     'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses' | ||||||
|  |   ); | ||||||
|  |   return currentUser; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default getCurrentUser; | ||||||
							
								
								
									
										13
									
								
								packages/backend/src/apps/gmail/dynamic-data/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								packages/backend/src/apps/gmail/dynamic-data/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import listEmails from './list-emails/index.js'; | ||||||
|  | import listLabels from './list-labels/index.js'; | ||||||
|  | import listMessages from './list-messages/index.js'; | ||||||
|  | import listSignatures from './list-signatures/index.js'; | ||||||
|  | import listThreads from './list-threads/index.js'; | ||||||
|  |  | ||||||
|  | export default [ | ||||||
|  |   listEmails, | ||||||
|  |   listLabels, | ||||||
|  |   listMessages, | ||||||
|  |   listSignatures, | ||||||
|  |   listThreads, | ||||||
|  | ]; | ||||||
| @@ -0,0 +1,23 @@ | |||||||
|  | import getCurrentUser from '../../common/get-current-user.js'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'List emails', | ||||||
|  |   key: 'listEmails', | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const emails = { | ||||||
|  |       data: [], | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const currentUser = await getCurrentUser($); | ||||||
|  |  | ||||||
|  |     for (const emailAddress of currentUser.emailAddresses) { | ||||||
|  |       emails.data.push({ | ||||||
|  |         value: emailAddress.value, | ||||||
|  |         name: emailAddress.value, | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return emails; | ||||||
|  |   }, | ||||||
|  | }; | ||||||
| @@ -0,0 +1,22 @@ | |||||||
|  | export default { | ||||||
|  |   name: 'List labels', | ||||||
|  |   key: 'listLabels', | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const labels = { | ||||||
|  |       data: [], | ||||||
|  |     }; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.get(`/gmail/v1/users/${userId}/labels`); | ||||||
|  |  | ||||||
|  |     for (const label of data.labels) { | ||||||
|  |       labels.data.push({ | ||||||
|  |         value: label.id, | ||||||
|  |         name: label.name, | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return labels; | ||||||
|  |   }, | ||||||
|  | }; | ||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | export default { | ||||||
|  |   name: 'List messages', | ||||||
|  |   key: 'listMessages', | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const messages = { | ||||||
|  |       data: [], | ||||||
|  |     }; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.get(`/gmail/v1/users/${userId}/messages`); | ||||||
|  |  | ||||||
|  |     if (data.messages) { | ||||||
|  |       for (const message of data.messages) { | ||||||
|  |         const { data: messageData } = await $.http.get( | ||||||
|  |           `/gmail/v1/users/${userId}/messages/${message.id}` | ||||||
|  |         ); | ||||||
|  |         const subject = messageData.payload.headers.find( | ||||||
|  |           (header) => header.name === 'Subject' | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         messages.data.push({ | ||||||
|  |           value: message.id, | ||||||
|  |           name: subject?.value, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return messages; | ||||||
|  |   }, | ||||||
|  | }; | ||||||
| @@ -0,0 +1,24 @@ | |||||||
|  | export default { | ||||||
|  |   name: 'List signatures', | ||||||
|  |   key: 'listSignatures', | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const signatures = { | ||||||
|  |       data: [], | ||||||
|  |     }; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.get( | ||||||
|  |       `/gmail/v1/users/${userId}/settings/sendAs` | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     for (const sendAs of data.sendAs) { | ||||||
|  |       signatures.data.push({ | ||||||
|  |         value: sendAs.signature, | ||||||
|  |         name: sendAs.sendAsEmail, | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return signatures; | ||||||
|  |   }, | ||||||
|  | }; | ||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | export default { | ||||||
|  |   name: 'List threads', | ||||||
|  |   key: 'listThreads', | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const threads = { | ||||||
|  |       data: [], | ||||||
|  |     }; | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |  | ||||||
|  |     const { data } = await $.http.get(`/gmail/v1/users/${userId}/threads`); | ||||||
|  |  | ||||||
|  |     if (data.threads) { | ||||||
|  |       for (const thread of data.threads) { | ||||||
|  |         const { data: threadData } = await $.http.get( | ||||||
|  |           `/gmail/v1/users/${userId}/threads/${thread.id}` | ||||||
|  |         ); | ||||||
|  |         const subject = threadData.messages[0].payload.headers.find( | ||||||
|  |           (header) => header.name === 'Subject' | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         threads.data.push({ | ||||||
|  |           value: thread.id, | ||||||
|  |           name: subject?.value, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return threads; | ||||||
|  |   }, | ||||||
|  | }; | ||||||
							
								
								
									
										22
									
								
								packages/backend/src/apps/gmail/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/backend/src/apps/gmail/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | import defineApp from '../../helpers/define-app.js'; | ||||||
|  | import addAuthHeader from './common/add-auth-header.js'; | ||||||
|  | import auth from './auth/index.js'; | ||||||
|  | import triggers from './triggers/index.js'; | ||||||
|  | import dynamicData from './dynamic-data/index.js'; | ||||||
|  | import actions from './actions/index.js'; | ||||||
|  |  | ||||||
|  | export default defineApp({ | ||||||
|  |   name: 'Gmail', | ||||||
|  |   key: 'gmail', | ||||||
|  |   baseUrl: 'https://mail.google.com', | ||||||
|  |   apiBaseUrl: 'https://gmail.googleapis.com', | ||||||
|  |   iconUrl: '{BASE_URL}/apps/gmail/assets/favicon.svg', | ||||||
|  |   authDocUrl: 'https://automatisch.io/docs/apps/gmail/connection', | ||||||
|  |   primaryColor: 'ea4335', | ||||||
|  |   supportsConnections: true, | ||||||
|  |   beforeRequest: [addAuthHeader], | ||||||
|  |   auth, | ||||||
|  |   triggers, | ||||||
|  |   dynamicData, | ||||||
|  |   actions, | ||||||
|  | }); | ||||||
							
								
								
									
										3
									
								
								packages/backend/src/apps/gmail/triggers/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/backend/src/apps/gmail/triggers/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | import newEmails from './new-emails/index.js'; | ||||||
|  |  | ||||||
|  | export default [newEmails]; | ||||||
							
								
								
									
										68
									
								
								packages/backend/src/apps/gmail/triggers/new-emails/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								packages/backend/src/apps/gmail/triggers/new-emails/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | import defineTrigger from '../../../../helpers/define-trigger.js'; | ||||||
|  |  | ||||||
|  | export default defineTrigger({ | ||||||
|  |   name: 'New emails', | ||||||
|  |   key: 'newEmails', | ||||||
|  |   pollInterval: 15, | ||||||
|  |   description: | ||||||
|  |     'Triggers when a new email is received in the specified mailbox.', | ||||||
|  |   arguments: [ | ||||||
|  |     { | ||||||
|  |       label: 'Label', | ||||||
|  |       key: 'labelId', | ||||||
|  |       type: 'dropdown', | ||||||
|  |       required: false, | ||||||
|  |       description: | ||||||
|  |         "If you don't choose a label, this Zap will trigger for all emails, including Drafts.", | ||||||
|  |       variables: true, | ||||||
|  |       source: { | ||||||
|  |         type: 'query', | ||||||
|  |         name: 'getDynamicData', | ||||||
|  |         arguments: [ | ||||||
|  |           { | ||||||
|  |             name: 'key', | ||||||
|  |             value: 'listLabels', | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  |  | ||||||
|  |   async run($) { | ||||||
|  |     const userId = $.auth.data.userId; | ||||||
|  |     const labelId = $.step.parameters.labelId; | ||||||
|  |  | ||||||
|  |     const params = { | ||||||
|  |       maxResults: 500, | ||||||
|  |       pageToken: undefined, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if (labelId) { | ||||||
|  |       params.labelIds = labelId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     do { | ||||||
|  |       const { data } = await $.http.get(`/gmail/v1/users/${userId}/messages`, { | ||||||
|  |         params, | ||||||
|  |       }); | ||||||
|  |       params.pageToken = data.nextPageToken; | ||||||
|  |  | ||||||
|  |       if (!data?.messages?.length) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       for (const message of data.messages) { | ||||||
|  |         const { data: messageData } = await $.http.get( | ||||||
|  |           `/gmail/v1/users/${userId}/messages/${message.id}` | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $.pushTriggerItem({ | ||||||
|  |           raw: messageData, | ||||||
|  |           meta: { | ||||||
|  |             internalId: messageData.id, | ||||||
|  |           }, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } while (params.pageToken); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
| @@ -141,6 +141,16 @@ export default defineConfig({ | |||||||
|             { text: 'Connection', link: '/apps/gitlab/connection' }, |             { text: 'Connection', link: '/apps/gitlab/connection' }, | ||||||
|           ], |           ], | ||||||
|         }, |         }, | ||||||
|  |         { | ||||||
|  |           text: 'Gmail', | ||||||
|  |           collapsible: true, | ||||||
|  |           collapsed: true, | ||||||
|  |           items: [ | ||||||
|  |             { text: 'Triggers', link: '/apps/gmail/triggers' }, | ||||||
|  |             { text: 'Connection', link: '/apps/gmail/connection' }, | ||||||
|  |             { text: 'Actions', link: '/apps/gmail/actions' }, | ||||||
|  |           ], | ||||||
|  |         }, | ||||||
|         { |         { | ||||||
|           text: 'Google Calendar', |           text: 'Google Calendar', | ||||||
|           collapsible: true, |           collapsible: true, | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								packages/docs/pages/apps/gmail/actions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/docs/pages/apps/gmail/actions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | --- | ||||||
|  | favicon: /favicons/gmail.svg | ||||||
|  | items: | ||||||
|  |   - name: Create draft | ||||||
|  |     desc: Create a new draft email message. | ||||||
|  |   - name: Reply to email | ||||||
|  |     desc: Respond to an email. | ||||||
|  |   - name: Send email | ||||||
|  |     desc: Send a new email message. | ||||||
|  |   - name: Send to trash | ||||||
|  |     desc: Send an existing email message to the trash. | ||||||
|  |   - name: Star an email | ||||||
|  |     desc: Star an email message. | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | <script setup> | ||||||
|  |   import CustomListing from '../../components/CustomListing.vue' | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <CustomListing /> | ||||||
							
								
								
									
										28
									
								
								packages/docs/pages/apps/gmail/connection.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								packages/docs/pages/apps/gmail/connection.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | # Gmail | ||||||
|  |  | ||||||
|  | :::info | ||||||
|  | This page explains the steps you need to follow to set up the Gmail | ||||||
|  | connection in Automatisch. If any of the steps are outdated, please let us know! | ||||||
|  | ::: | ||||||
|  |  | ||||||
|  | 1. Go to the [Google Cloud Console](https://console.cloud.google.com) to create a project. | ||||||
|  | 2. Click on the project drop-down menu at the top of the page, and click on the **New Project** button. | ||||||
|  | 3. Enter a name for your project and click on the **Create** button. | ||||||
|  | 4. Go to [API Library](https://console.cloud.google.com/apis/library) in Google Cloud console. | ||||||
|  | 5. Search for **People API** in the search bar and click on it. | ||||||
|  | 6. Click on the **Enable** button to enable the API. | ||||||
|  | 7. Repeat steps 5 and 6 for the **Gmail API** | ||||||
|  | 8. Go to [OAuth consent screen](https://console.cloud.google.com/apis/credentials/consent) in Google Cloud console. | ||||||
|  | 9. Select **External** here for starting your app in testing mode at first. Click on the **Create** button. | ||||||
|  | 10. Fill **App Name**, **User Support Email**, and **Developer Contact Information**. Click on the **Save and Continue** button. | ||||||
|  | 11. Skip adding or removing scopes and click on the **Save and Continue** button. | ||||||
|  | 12. Click on the **Add Users** button and add a test email because only test users can access the app while publishing status is set to "Testing". | ||||||
|  | 13. Click on the **Save and Continue** button and now you have configured the consent screen. | ||||||
|  | 14. Go to [Credentials](https://console.cloud.google.com/apis/credentials) in Google Cloud console. | ||||||
|  | 15. Click on the **Create Credentials** button and select the **OAuth client ID** option. | ||||||
|  | 16. Select the application type as **Web application** and fill the **Name** field. | ||||||
|  | 17. Copy **OAuth Redirect URL** from Automatisch to **Authorized redirect URIs** field, and click on the **Create** button. | ||||||
|  | 18. Copy the **Your Client ID** value from the following popup to the `Client ID` field on Automatisch. | ||||||
|  | 19. Copy the **Your Client Secret** value from the following popup to the `Client Secret` field on Automatisch. | ||||||
|  | 20. Click **Submit** button on Automatisch. | ||||||
|  | 21. Congrats! Start using your new Gmail connection within the flows. | ||||||
							
								
								
									
										12
									
								
								packages/docs/pages/apps/gmail/triggers.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/docs/pages/apps/gmail/triggers.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | --- | ||||||
|  | favicon: /favicons/gmail.svg | ||||||
|  | items: | ||||||
|  |   - name: New emails | ||||||
|  |     desc: Triggers when a new email is received in the specified mailbox. | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | <script setup> | ||||||
|  |   import CustomListing from '../../components/CustomListing.vue' | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <CustomListing /> | ||||||
| @@ -14,6 +14,7 @@ The following integrations are currently supported by Automatisch. | |||||||
| - [Ghost](/apps/ghost/triggers) | - [Ghost](/apps/ghost/triggers) | ||||||
| - [GitHub](/apps/github/triggers) | - [GitHub](/apps/github/triggers) | ||||||
| - [GitLab](/apps/gitlab/triggers) | - [GitLab](/apps/gitlab/triggers) | ||||||
|  | - [Gmail](/apps/gmail/triggers) | ||||||
| - [Google Calendar](/apps/google-calendar/triggers) | - [Google Calendar](/apps/google-calendar/triggers) | ||||||
| - [Google Drive](/apps/google-drive/triggers) | - [Google Drive](/apps/google-drive/triggers) | ||||||
| - [Google Forms](/apps/google-forms/triggers) | - [Google Forms](/apps/google-forms/triggers) | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								packages/docs/pages/public/favicons/gmail.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								packages/docs/pages/public/favicons/gmail.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 49.4 512 399.42"> | ||||||
|  |   <g fill="none" fill-rule="evenodd"> | ||||||
|  |     <g fill-rule="nonzero"> | ||||||
|  |       <path fill="#4285f4" d="M34.91 448.818h81.454V251L0 163.727V413.91c0 19.287 15.622 34.91 34.91 34.91z"/> | ||||||
|  |       <path fill="#34a853" d="M395.636 448.818h81.455c19.287 0 34.909-15.622 34.909-34.909V163.727L395.636 251z"/> | ||||||
|  |       <path fill="#fbbc04" d="M395.636 99.727V251L512 163.727v-46.545c0-43.142-49.25-67.782-83.782-41.891z"/> | ||||||
|  |     </g> | ||||||
|  |     <path fill="#ea4335" d="M116.364 251V99.727L256 204.455 395.636 99.727V251L256 355.727z"/> | ||||||
|  |     <path fill="#c5221f" fill-rule="nonzero" d="M0 117.182v46.545L116.364 251V99.727L83.782 75.291C49.25 49.4 0 74.04 0 117.18z"/> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 720 B | 
		Reference in New Issue
	
	Block a user