diff --git a/packages/backend/src/apps/smtp/assets/favicon.svg b/packages/backend/src/apps/smtp/assets/favicon.svg
new file mode 100644
index 00000000..57f0fa58
--- /dev/null
+++ b/packages/backend/src/apps/smtp/assets/favicon.svg
@@ -0,0 +1,4 @@
+
diff --git a/packages/backend/src/apps/smtp/auth/index.ts b/packages/backend/src/apps/smtp/auth/index.ts
new file mode 100644
index 00000000..900c9278
--- /dev/null
+++ b/packages/backend/src/apps/smtp/auth/index.ts
@@ -0,0 +1,210 @@
+import verifyCredentials from './verify-credentials';
+import isStillVerified from './is-still-verified';
+
+export default {
+ fields: [
+ {
+ key: 'host',
+ label: 'Host',
+ type: 'string',
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description: 'The host information Automatisch will connect to.',
+ docUrl: 'https://automatisch.io/docs/smtp#host',
+ clickToCopy: false,
+ },
+ {
+ key: 'username',
+ label: 'Email/Username',
+ type: 'string',
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description: 'Your SMTP login credentials.',
+ docUrl: 'https://automatisch.io/docs/smtp#username',
+ clickToCopy: false,
+ },
+ {
+ key: 'password',
+ label: 'Password',
+ type: 'string',
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description: null,
+ docUrl: 'https://automatisch.io/docs/smtp#password',
+ clickToCopy: false,
+ },
+ {
+ key: 'useTls',
+ label: 'Use TLS?',
+ type: 'dropdown',
+ required: false,
+ readOnly: false,
+ value: false,
+ placeholder: null,
+ description: null,
+ docUrl: 'https://automatisch.io/docs/smtp#use-tls',
+ clickToCopy: false,
+ options: [
+ {
+ label: 'Yes',
+ value: true,
+ },
+ {
+ label: 'No',
+ value: false,
+ },
+ ],
+ },
+ {
+ key: 'port',
+ label: 'Port',
+ type: 'integer',
+ required: false,
+ readOnly: false,
+ value: 25,
+ placeholder: null,
+ description: null,
+ docUrl: 'https://automatisch.io/docs/smtp#port',
+ clickToCopy: false,
+ },
+ {
+ key: 'fromEmail',
+ label: 'From Email',
+ type: 'string',
+ required: false,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description: null,
+ docUrl: 'https://automatisch.io/docs/smtp#from-email',
+ clickToCopy: false,
+ },
+ ],
+ authenticationSteps: [
+ {
+ step: 1,
+ type: 'mutation',
+ name: 'createConnection',
+ fields: [
+ {
+ name: 'key',
+ value: '{key}',
+ },
+ {
+ name: 'data',
+ value: null,
+ fields: [
+ {
+ name: 'host',
+ value: '{fields.host}',
+ },
+ {
+ name: 'username',
+ value: '{fields.username}',
+ },
+ {
+ name: 'password',
+ value: '{fields.password}',
+ },
+ {
+ name: 'useTLS',
+ value: '{fields.useTls}',
+ },
+ {
+ name: 'port',
+ value: '{fields.port}',
+ },
+ {
+ name: 'fromEmail',
+ value: '{fields.fromEmail}',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ step: 2,
+ type: 'mutation',
+ name: 'verifyConnection',
+ fields: [
+ {
+ name: 'id',
+ value: '{createConnection.id}',
+ },
+ ],
+ },
+ ],
+ reconnectionSteps: [
+ {
+ step: 1,
+ type: 'mutation',
+ name: 'resetConnection',
+ fields: [
+ {
+ name: 'id',
+ value: '{connection.id}',
+ },
+ ],
+ },
+ {
+ step: 2,
+ type: 'mutation',
+ name: 'updateConnection',
+ fields: [
+ {
+ name: 'id',
+ value: '{connection.id}',
+ },
+ {
+ name: 'data',
+ value: null,
+ fields: [
+ {
+ name: 'host',
+ value: '{fields.host}',
+ },
+ {
+ name: 'username',
+ value: '{fields.username}',
+ },
+ {
+ name: 'password',
+ value: '{fields.password}',
+ },
+ {
+ name: 'useTLS',
+ value: '{fields.useTls}',
+ },
+ {
+ name: 'port',
+ value: '{fields.port}',
+ },
+ {
+ name: 'fromEmail',
+ value: '{fields.fromEmail}',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ step: 3,
+ type: 'mutation',
+ name: 'verifyConnection',
+ fields: [
+ {
+ name: 'id',
+ value: '{connection.id}',
+ },
+ ],
+ },
+ ],
+ verifyCredentials,
+ isStillVerified,
+};
diff --git a/packages/backend/src/apps/smtp/auth/is-still-verified.ts b/packages/backend/src/apps/smtp/auth/is-still-verified.ts
new file mode 100644
index 00000000..95a1ef29
--- /dev/null
+++ b/packages/backend/src/apps/smtp/auth/is-still-verified.ts
@@ -0,0 +1,13 @@
+import { IGlobalVariable } from '@automatisch/types';
+import verifyCredentials from './verify-credentials';
+
+const isStillVerified = async ($: IGlobalVariable) => {
+ try {
+ await verifyCredentials($);
+ return true;
+ } catch (error) {
+ return false;
+ }
+};
+
+export default isStillVerified;
diff --git a/packages/backend/src/apps/smtp/auth/verify-credentials.ts b/packages/backend/src/apps/smtp/auth/verify-credentials.ts
new file mode 100644
index 00000000..22189967
--- /dev/null
+++ b/packages/backend/src/apps/smtp/auth/verify-credentials.ts
@@ -0,0 +1,22 @@
+import { IGlobalVariable } from '@automatisch/types';
+import nodemailer, { TransportOptions } from 'nodemailer';
+
+const verifyCredentials = async ($: IGlobalVariable) => {
+ const client = nodemailer.createTransport({
+ host: $.auth.data.host,
+ port: $.auth.data.port,
+ secure: $.auth.data.useTls,
+ auth: {
+ user: $.auth.data.username,
+ pass: $.auth.data.password,
+ },
+ } as TransportOptions);
+
+ await client.verify();
+
+ await $.auth.set({
+ screenName: $.auth.data.username,
+ });
+};
+
+export default verifyCredentials;
diff --git a/packages/backend/src/apps/smtp/index.ts b/packages/backend/src/apps/smtp/index.ts
new file mode 100644
index 00000000..9a0a7f94
--- /dev/null
+++ b/packages/backend/src/apps/smtp/index.ts
@@ -0,0 +1,13 @@
+import defineApp from '../../helpers/define-app';
+
+export default defineApp({
+ name: 'SMTP',
+ key: 'smtp',
+ iconUrl: '{BASE_URL}/apps/smtp/assets/favicon.svg',
+ authDocUrl: 'https://automatisch.io/docs/connections/smtp',
+ supportsConnections: true,
+ baseUrl: '',
+ apiBaseUrl: '',
+ primaryColor: '2DAAE1',
+ beforeRequest: [],
+});
diff --git a/packages/backend/src/models/app.ts b/packages/backend/src/models/app.ts
index 958eee1c..87ec8158 100644
--- a/packages/backend/src/models/app.ts
+++ b/packages/backend/src/models/app.ts
@@ -16,6 +16,7 @@ class App {
'scheduler',
'slack',
'twitter',
+ 'smtp',
];
static async findAll(name?: string, stripFuncs = true): Promise {