Giter Site home page Giter Site logo

parse-server-api-mail-adapter's Introduction

Parse Server API Mail Adapter

Build Status Snyk Badge Coverage auto-release

Node Version

npm latest version


The Parse Server API Mail Adapter enables Parse Server to send emails using any 3rd party API with built-in dynamic templates and localization.

Transfer

ℹ️ This repository has been transferred to the Parse Platform Organization on May 15, 2022. Please update any links that you may have to this repository, for example if you cloned or forked this repository and maintain a remote link to this original repository, or if you are referencing a GitHub commit directly as your dependency.


Content

Installation

  1. Install adapter:
    npm install --save parse-server-api-mail-adapter
    
  2. Add template files to a subdirectory.
  3. Add adapter configuration to Parse Server.

Demo

The demo script makes it easy to test adapter configurations and templates by sending emails without Parse Server via the email service provider Mailgun:

  1. Create a file mailgun.json in the demo directory with the following content:
    {
        "key": "MAILGUN_API_KEY", // e.g. abc123
        "domain": "MAILGUN_DOMAIN", // e.g. [email protected]
        "sender": "SENDER_EMAIL", // e.g. [email protected]
        "recipient": "RECIPIENT_EMAIL" // e.g. [email protected]
    }
  2. Run node ./demo to execute the script and send an email.

You can modify the script to use any other API you like or debug-step through the sending process to better understand the adapter internals.

Configuration

An example configuration to add the API Mail Adapter to Parse Server could look like this:

const Mailgun = require('mailgun.js');
const formData = require('form-data');
const { ApiPayloadConverter } = require('parse-server-api-mail-adapter');

// Configure mail client
const mailgun = new Mailgun(formData);
const mailgunClient = mailgun.client({ username: 'api', key: process.env.MAILGUN_API_KEY });
const mailgunDomain = process.env.MAILGUN_DOMAIN;

// Configure Parse Server
const server = new ParseServer({
    ...otherServerOptions,

    emailAdapter: {
        module: 'parse-server-api-mail-adapter',
        options: {
            // The email address from which emails are sent.
            sender: '[email protected]',
            // The email templates.
            templates: {
                // The template used by Parse Server to send an email for password
                // reset; this is a reserved template name.
                passwordResetEmail: {
                    subjectPath: './files/password_reset_email_subject.txt',
                    textPath: './files/password_reset_email.txt',
                    htmlPath: './files/password_reset_email.html'
                },
                // The template used by Parse Server to send an email for email
                // address verification; this is a reserved template name.
                verificationEmail: {
                    subjectPath: './files/verification_email_subject.txt',
                    textPath: './files/verification_email.txt',
                    htmlPath: './files/verification_email.html'
                },
                // A custom email template that can be used when sending emails
                // from Cloud Code; the template name can be chosen freely; it
                // is possible to add various custom templates.
                customEmail: {
                    subjectPath: './files/custom_email_subject.txt',
                    textPath: './files/custom_email.txt',
                    htmlPath: './files/custom_email.html',
                    // Placeholders are filled into the template file contents.
                    // For example, the placeholder `{{appName}}` in the email
                    // will be replaced the value defined here.
                    placeholders: {
                        appName: "ExampleApp"
                    },
                    // Extras to add to the email payload that is accessible in the
                    // `apiCallback`.
                    extra: {
                        replyTo: '[email protected]'
                    },
                    // A callback that makes the Parse User accessible and allows
                    // to return user-customized placeholders that will override
                    // the default template placeholders. It also makes the user
                    // locale accessible, if it was returned by the `localeCallback`,
                    // and the current placeholders that will be augmented.
                    placeholderCallback: async ({ user, locale, placeholders }) => {
                        return {
                            phone: user.get('phone');
                        };
                    },
                    // A callback that makes the Parse User accessible and allows
                    // to return the locale of the user for template localization.
                    localeCallback: async (user) => {
                        return user.get('locale');
                    }
                }
            },
            // The asynchronous callback that contains the composed email payload to
            // be passed on to an 3rd party API and optional meta data. The payload
            // may need to be converted specifically for the API; conversion for
            // common APIs is conveniently available in the `ApiPayloadConverter`.
            // Below is an example for the Mailgun client.
            apiCallback: async ({ payload, locale }) => {
                const mailgunPayload = ApiPayloadConverter.mailgun(payload);
                await mailgunClient.messages.create(mailgunDomain, mailgunPayload);
            }
        }
    }
});

Templates

Emails are composed using templates. A template defines the paths to its content files, for example:

templates: {
    exampleTemplate: {
        subjectPath: './files/custom_email_subject.txt',
        textPath: './files/custom_email.txt',
        htmlPath: './files/custom_email.html',
    }
},

There are different files for different parts of the email:

  • subject (subjectPath)
  • plain-text content (textPath)
  • HTML content (htmlPath)

See the templates for examples how placeholders can be used.

Placeholders

Placeholders allow to dynamically insert text into the template content. The placeholder values are filled in according to the key-value definitions returned by the placeholder callback in the adapter configuration.

This is using the mustache template syntax. The most commonly used tags are:

  • {{double-mustache}}: The most basic form of tag; inserts text as HTML escaped by default.
  • {{{triple-mustache}}}: Inserts text with unescaped HTML, which is required to insert a URL for example.

Password Reset and Email Verification

By default, the following placeholders are available in the password reset and email verification templates:

  • {{appName}}: The app name as set in the Parse Server configuration.
  • {{username}}: The username of the user who requested the email.
  • {{link}}: The URL to the Parse Server endpoint for password reset or email verification.

Localization

Localization allows to use a specific template depending on the user locale. To turn on localization for a template, add a localeCallback to the template configuration.

The locale returned by localeCallback will be used to look for locale-specific template files. If the callback returns an invalid locale or nothing at all (undefined), localization will be ignored and the default files will be used.

The locale-specific files are placed in sub-folders with the name of either the whole locale (e.g. de-AT), or only the language (e.g. de). The locale has to be in format [language]-[country] as specified in IETF BCP 47, e.g. de-AT.

Localized files are placed in sub-folders of the given path, for example:

base/
├── example.html         // default file
└── de/                  // de language folder
   └── example.html     // de localized file
└── de-AT/               // de-AT locale folder
   └── example.html     // de-AT localized file

Files are matched with the user locale in the following order:

  1. Locale (locale de-AT matches file in folder de-AT)
  2. Language (locale de-AT matches file in folder de if there is no file in folder de-AT)
  3. Default (default file in base folder is returned if there is no file in folders de-AT and de)

Cloud Code

Sending an email directly from Cloud Code is possible since Parse Server > 4.5.0. This adapter supports this convenience method.

Example

If the user provided has an email address set, it is not necessary to set a recipient because the mail adapter will by default use the mail address of the user.

Parse.Cloud.sendEmail({
  templateName: "next_level_email",
  placeholders: { gameScore: 100, nextLevel: 2 },
  user: parseUser // user with email address
});

Parameters

Parameter Type Optional Default Value Example Value Description
sender String - [email protected] The email sender address; overrides the sender address specified in the adapter configuration.
recipient String - [email protected] The email recipient; if set overrides the email address of the user.
subject String - Welcome The email subject.
text String - Thank you for signing up! The plain-text email content.
html String yes undefined <html>...</html> The HTML email content.
templateName String yes undefined customTemplate The template name.
placeholders Object yes {} { key: value } The template placeholders.
extra Object yes {} { key: value } Any additional variables to pass to the mail provider API.
user Parse.User yes undefined - The Parse User that the is the recipient of the email.

Supported APIs

This adapter supports any REST API by adapting the API payload in the adapter configuration apiCallback according to the API specification.

Providers

For convenience, support for common APIs is already built into this adapter and available via the ApiPayloadConverter. The following is a list of currently supported API providers:

If the provider you are using is not already supported, please feel free to open a PR.

Example for Mailgun

This is an example for the Mailgun client:

// Configure mail client
const mailgun = require('mailgun.js');
const mailgunClient = mailgun.client({ username: 'api', key: process.env.MAILGUN_API_KEY });
const mailgunDomain = process.env.MAILGUN_DOMAIN;

// Configure Parse Server
const server = new ParseServer({
    ...otherServerOptions,

    emailAdapter: {
        module: 'parse-server-api-mail-adapter',
        options: {
            ... otherAdapterOptions,

            apiCallback: async ({ payload, locale }) => {
                const mailgunPayload = ApiPayloadConverter.mailgun(payload);
                await mailgunClient.messages.create(mailgunDomain, mailgunPayload);
            }
        }
    }
});

Example for AWS Simple Email Service

This is an example for the AWS Simple Email Service client using the AWS JavaScript SDK v3:

// Configure mail client
const { SES, SendEmailCommand } = require('@aws-sdk/client-ses');

const {
  fromInstanceMetadata, // Get credentials via IMDS from the AWS instance (when deployed on AWS instance)
  fromEnv, // Get AWS credentials from environment variables (when testing locally)
} = require('@aws-sdk/credential-providers');

// Get AWS credentials depending on environment
const credentialProvider= process.env.NODE_ENV == 'production' ? fromInstanceMetadata() : fromEnv();
const credentials = await credentialProvider();

const sesClient = new SES({
    credentials,
    region: 'eu-west-1',
    apiVersion: '2010-12-01'
});

// Configure Parse Server
const server = new ParseServer({
    ...otherServerOptions,

    emailAdapter: {
        module: 'parse-server-api-mail-adapter',
        options: {
            ... otherAdapterOptions,

            apiCallback: async ({ payload, locale }) => {
                const awsSesPayload = ApiPayloadConverter.awsSes(payload);
                const command = new SendEmailCommand(awsSesPayload);
                await sesClient.send(command);
            }
        }
    }
});

Custom API

This is an example of how the API payload can be adapted in the adapter configuration apiCallback according to a custom email provider's API specification.

// Configure mail client
const customMail = require('customMail.js');
const customMailClient = customMail.configure({ ... });

// Configure Parse Server
const server = new ParseServer({
    ...otherOptions,

    emailAdapter: {
        module: 'parse-server-api-mail-adapter',
        options: {
            ... otherOptions,

            apiCallback: async ({ payload, locale }) => {
                const customPayload = {
                    customFrom: payload.from,
                    customTo: payload.to,
                    customSubject: payload.subject,
                    customText: payload.text
                };
                await customMailClient.sendEmail(customPayload);
            }
        }
    }
});

Need help?

  • Ask on StackOverflow using the parse-server tag.
  • Search through existing issues or open a new issue.

parse-server-api-mail-adapter's People

Contributors

dependabot[bot] avatar funkenstrahlen avatar mtrezza avatar semantic-release-bot avatar tbjers avatar wlky avatar woutercouvaras avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

parse-server-api-mail-adapter's Issues

Use locale identifier from Parse Installation instead of user to localize mails

New Feature / Enhancement Checklist

Current Limitation

Localization can only be decided by properties of user object but parse automatically stores user localization data in Parse Installation.

Feature / Enhancement Description

Allow access to Parse Installation in localization callback of a template

Example Use Case

Parse Installation already comes with a valid locale identifier in the database. Parse User does not and it requires extra effort to store the localization preferences there.

Alternatives / Workarounds

Parse Installation Post Save Hook to store localization preferences in Parse User too.

The automated release is failing 🚨

🚨 The automated release from the alpha branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can fix this 💪.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the alpha branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here are some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.

If you are using Two Factor Authentication for your account, set its level to "Authorization only" in your account settings. semantic-release cannot publish with the default "
Authorization and writes" level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.


Good luck with your project ✨

Your semantic-release bot 📦🚀

TypeError [ERR_INVALID_ARG_TYPE] when sending email

Issue Description

Getting error
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined

Steps to reproduce

have installed v4.10.4 Parse server on mac and this adaptor. using this function from cloud code

function sendEmailViaParseAPI(sender, recipient, subject, textBody, htmlBody) {
 
 Parse.Cloud.sendEmail({
    sender: sender,
    recipient: recipient,
    subject: subject,
    text: textBody,
    html: htmlBody,
  });

}

I have created templates in files folder in my parse-server local folder.
from index.js

const Mailgun = require('mailgun.js');
const formData = require('form-data');
const mailgun = new Mailgun(formData);
const mailgunClient = mailgun.client({ username: 'api', key: process.env.MAILGUN_API_KEY });
const mailgunDomain = process.env.MAILGUN_DOMAIN;
const { ApiPayloadConverter } = require('parse-server-api-mail-adapter');
emailAdapter: {
    module: 'parse-server-api-mail-adapter',
    options: {
      sender: process.env.APP_SUPPORT_EMAIL,
      templates: {
        passwordResetEmail: {
            subjectPath: './files/password_reset_email_subject.txt',
            textPath: './files/password_reset_email.txt',
            htmlPath: './files/password_reset_email.html'
        },
        verificationEmail: {
            subjectPath: './files/verification_email_subject.txt',
            textPath: './files/verification_email.txt',
            htmlPath: './files/verification_email.html'
        },
      },
      apiCallback: async ({ payload, locale }) => {
        const mailgunPayload = ApiPayloadConverter.mailgun(payload);
        await mailgunClient.messages.create(mailgunDomain, mailgunPayload);
      }
    }
  }

Actual Outcome

(node:82294) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
    at open (internal/fs/promises.js:216:10)
    at Object.readFile (internal/fs/promises.js:517:20)
    at ApiMailAdapter._callee4$ (/Users/ashishn/Developer/parse-server-local/node_modules/parse-server-api-mail-adapter/lib/ApiMailAdapter.js:550:27)
    at tryCatch (/Users/ashishn/Developer/parse-server-local/node_modules/regenerator-runtime/runtime.js:63:40)
    at Generator.invoke [as _invoke] (/Users/ashishn/Developer/parse-server-local/node_modules/regenerator-runtime/runtime.js:293:22)
    at Generator.next (/Users/ashishn/Developer/parse-server-local/node_modules/regenerator-runtime/runtime.js:118:21)
    at asyncGeneratorStep (/Users/ashishn/Developer/parse-server-local/node_modules/parse-server-api-mail-adapter/lib/ApiMailAdapter.js:5:103)
    at _next (/Users/ashishn/Developer/parse-server-local/node_modules/parse-server-api-mail-adapter/lib/ApiMailAdapter.js:7:194)
    at /Users/ashishn/Developer/parse-server-local/node_modules/parse-server-api-mail-adapter/lib/ApiMailAdapter.js:7:364
    at new Promise (<anonymous>)

Environment

macOS 12.1

  • API Mail Adapter version: 2.1.0
  • Parse Server version: 4.10.4

Logs

as above

I could not understand running the demo.

I installed adaptor in a folder named "testmail " and ran node ./demo. it gave error module not found.
Ran it from ./node_modules/parse-server-api-mail-adapter but got error Error: Cannot find module 'form-data'

Pls help if i am missing anything out.

New Install required regenerator-runtime which is not in configuration or installation readme

New Issue Checklist

Issue Description

Going through the installation instructions from the README file, I get an error

ReferenceError: regeneratorRuntime is not defined

Which can be solved by requiring regenerator-runtime.

A quick update to the readme file requiring and installing regenerator-runtime fixes this.

Steps to reproduce

New installation on a clean parse-server will produce this issue.

Actual Outcome

error ReferenceError: regeneratorRuntime is not defined

Expected Outcome

ReadMe should mention the requirement for regenerator-runtime for people not as tech savvy like I am.

Failing Test Case / Pull Request

Environment

  • API Mail Adapter version: 6.0.1
  • Parse Server version: 5.2.1

Logs

Remove pre-release branches

New Feature / Enhancement Checklist

Current Limitation

As we've seen over the past year, the pre-release branches alpha, beta are of little use in Parse Server modules since they have a low release frequency. The additional work to manage pre-releases isn't worth it given the few PRs that are actually occurring in these modules.

Feature / Enhancement Description

  • Remove auto-release for pre-release branches
  • Lock existing pre-release branches alpha, beta
  • Change GitHub working branch to release branch

That means, any PRs will be merged into the release branch. There won't be any new alpha or beta releases published.

Add TypeScript definitions

New Feature / Enhancement Checklist

Current Limitation

Type declaration comments are stripped out by Babel.

Feature / Enhancement Description

Add TypeScript definition files as outlined in Creating .d.ts Files from .js files in the TypeScript documentation.

Example Use Case

  1. Add type definitions to lib/ directory.
  2. Update build step in package.json with && tsc.
  3. Definitions will be included when publishing the package.
  4. Rejoice.

Alternatives / Workarounds

No alternatives or workarounds exist.

3rd Party References

There is no @types/parse-server-api-mail-adapter package.

Locale callback throwing an error when sending email through cloud code

New Issue Checklist

Issue Description

When I try to send a templated email with locale callback the cloud code throws an error
cannot find function get of undefined

Steps to reproduce

setup a custom email template with locale callback.

localeCallback: async (user: any) => {
       return user.get('language');
 }
Call it from the cloud code like so:
    Parse.Cloud.sendEmail({
      templateName: "custom_email",
      recipient: [email protected],
      placeholders: request.params.placeholders
    });

(Only works for current Parse server master branch, parse-server 4.5 doesn't have the sendEmail function yet)

Actual Outcome

Error, cant find method get of undefined error when the locale callback code is executed

Expected Outcome

Correct locale email gets sent

Failing Test Case / Pull Request

#18

Environment

  • API Mail Adapter version: 1.0.4
  • Parse Server version: Master branch

Logs

don't have them any more^^

Extra values are not present in callback payload

New Issue Checklist

Issue Description

When additional properties are defined in sendMail(options), they aren't present in the payload of the callback.

Steps to reproduce

Parse.Cloud.sendEmail({
      templateName: 'testTemplate',
      placeholders: {
        name: 'Test',
      },
      recipient: '[email protected]',
      extra: {
        testKey: 'testValue'
      }
})

Actual Outcome

config.emailAdapter = {
    module: 'parse-server-api-mail-adapter',
    options: {
      sender: '..',
      templates: { ... },
      apiCallback: async ({ payload, locale }) => {
        console.log(payload)
      })
  }
}

output:

{
  from: '...',
  to: '...',
  subject: 'Test\n',
  text: '...',
  html: '<html>\n' +
    '  <body>\n' +
    '    <p>Test</p>\n' +    
    '  </body>\n' +
    '</html>\n'
}

Expected Outcome

The properties set in extra should be present somehow.

Failing Test Case / Pull Request

Environment

  • API Mail Adapter version: 3.1.1
  • Parse Server version: 6.4.0

Logs

Add semantic release

New Feature / Enhancement Checklist

Current Limitation

Currently no release automation.

Feature / Enhancement Description

  • Add semantic release
  • Add distribution channels @Alpha, @beta, @latest to mature features

Example Use Case

n/a

Alternatives / Workarounds

n/a

3rd Party References

n/a

Error: ApiMailAdapter: template content path is invalid

New Issue Checklist

Issue Description

I'm getting this error: Error: ApiMailAdapter: template content path is invalid with my config.
my filePath is E:\tiavina-mika\portfolio-v3\email\templates\projects\projectsSubject.txt

Steps to reproduce

here is my files:

mailgunConfig.js

const path = require('path');

const formData = require('form-data');
const Mailgun = require('mailgun.js');
const { ApiPayloadConverter } = require('parse-server-api-mail-adapter');

const filePath = (file, folder) => path.join(__dirname, 'templates/' + (folder ? folder + '/' : ''), file);

const getEmailAdapter = () => {
    // Configure mail client
    const mailgun = new Mailgun(formData);
    const mailgunClient = mailgun.client({ username: 'api', key: process.env.MAILGUN_API_KEY });
    const mailgunDomain = process.env.MAILGUN_DOMAIN;
    console.log('filePath(): ', filePath('projectsSubject.txt', 'projects'));
    const emailAdapter = {
        module: 'parse-server-api-mail-adapter',
        options: {
            // The email address from which emails are sent.
            sender: '[email protected]',
            // The email templates.
            templates: {
                // The template used by Parse Server to send an email for password
                // reset; this is a reserved template name.
                // passwordResetEmail: {
                //     subjectPath: './files/password_reset_email_subject.txt',
                //     textPath: './files/password_reset_email.txt',
                //     htmlPath: './files/password_reset_email.html'
                // },
                // // The template used by Parse Server to send an email for email
                // // address verification; this is a reserved template name.
                // verificationEmail: {
                //     subjectPath: './files/verification_email_subject.txt',
                //     textPath: './files/verification_email.txt',
                //     htmlPath: './files/verification_email.html'
                // },
                // A custom email template that can be used when sending emails
                // from Cloud Code; the template name can be chosen freely; it
                // is possible to add various custom templates.
                projectEmail: {
                    // subjectPath: './files/custom_email_subject.txt',
                    // textPath: './files/custom_email.txt',
                    // subjectPath: './emailTemplates/projects/projectsSubject.txt',
                    subjectPath: filePath('projectsSubject.txt', 'projects'),
                    htmlPath: filePath('projects.html', 'projects'),
                    // Placeholders are filled into the template file contents.
                    // For example, the placeholder `{{appName}}` in the email
                    // will be replaced the value defined here.
                    placeholders: {
                        appName: 'ExampleApp',
                    },
                    // Extras to add to the email payload that is accessible in the
                    // `apiCallback`.
                    // extra: {
                    //     replyTo: '[email protected]'
                    // },
                    // A callback that makes the Parse User accessible and allows
                    // to return user-customized placeholders that will override
                    // the default template placeholders. It also makes the user
                    // locale accessible, if it was returned by the `localeCallback`,
                    // and the current placeholders that will be augmented.
                    // placeholderCallback: async ({ user, locale, placeholders }) => {
                    //     return {
                    //         phone: user.get('phone');
                    //     };
                    // },
                    // A callback that makes the Parse User accessible and allows
                    // to return the locale of the user for template localization.
                    // localeCallback: async (user) => {
                    //     return user.get('locale');
                    // }
                },
            },
            // The asynchronous callback that contains the composed email payload to
            // be passed on to an 3rd party API and optional meta data. The payload
            // may need to be converted specifically for the API; conversion for
            // common APIs is conveniently available in the `ApiPayloadConverter`.
            // Below is an example for the Mailgun client.
            apiCallback: async ({ payload }) => {
                const mailgunPayload = ApiPayloadConverter.mailgun(payload);
                await mailgunClient.messages.create(mailgunDomain, mailgunPayload);
            },
        },
    };

    return emailAdapter;
};

exports.getEmailAdapter = getEmailAdapter;

server.js (Next.js custom server + express)

const express = require('express');
const ParseServer = require('parse-server').ParseServer;
const path = require('path');
const next = require('next');
const cors = require('cors');
const dotenv = require('dotenv');
const Parse = require('parse/node');
const { getEmailAdapter } = require('./mailgunConfig');

const SERVER_PORT = process.env.PORT || 3001;
const APP_ID = process.env.APP_ID || 'myApp';
global.APP_ID = APP_ID;
const MASTER_KEY = process.env.MASTER_KEY || 'xxxx';
const IS_DEVELOPMENT = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev: IS_DEVELOPMENT });
const handle = nextApp.getRequestHandler();

let envFileName;
let serverUrl;
if (IS_DEVELOPMENT) {
  envFileName = '.env.local';
  serverUrl = 'http://localhost:' + SERVER_PORT;
} else {
  envFileName = '.env.prod';
  serverUrl = 'https://my-app.herokuapp.com';
}

global.USE_MASTER_KEY = { useMasterKey: true };
global.IS_DEVELOPMENT = IS_DEVELOPMENT;

const result = dotenv.config({ path: path.join(__dirname, envFileName) });

if (result.error) {
  throw result.error;
}

const parseServerAPI = new ParseServer({
  databaseURI: process.env.DB_URL,
  cloud: path.resolve(__dirname, './cloud/main.js'),
  appId: APP_ID,
  masterKey: MASTER_KEY,
  serverURL: serverUrl + '/parse',

  // verifyUserEmails: true,
  // emailVerifyTokenValidityDuration: 2 * 60 * 60,
  // preventLoginWithUnverifiedEmail: false,
  emailAdapter: getEmailAdapter(),
});

global.USE_MASTER_KEY = { useMasterKey: true };
global.LOCAL = true;

nextApp
  .prepare()
  .then(() => {
    Parse.initialize('myApp');
    Parse.serverURL = `${serverUrl}/api/parse`;
    Parse.masterKey = MASTER_KEY;

    const app = express();

    app.use(cors());
    // Add headers
    app.use((req, res, next) => {
      // Set to true if you need the website to include cookies in the requests sent
      // to the API (e.g. in case you use sessions)
      res.setHeader('Access-Control-Allow-Credentials', true);

      // Pass to next layer of middleware
      next();
    });

    app.use('/parse', parseServerAPI);

    app.all('*', (req, res) => {
      return handle(req, res);
    });

    app.listen(SERVER_PORT, (err) => {
      if (err) throw err;
      console.log(
        `Notre serveur tourne en mode ${process.env.NODE_ENV ||
          'development'} sur ${serverUrl}`
      );
    });
  })
  .catch((error) => {
    console.error(error.stack);
    process.exit(1);
  });

folder structures

image

Actual Outcome

`
E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\ApiMailAdapter.js:601
throw Errors.Error.templateContentPathInvalid;
^

Error: ApiMailAdapter: template content path is invalid.
at Function.get (E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\Errors.js:62:37)
at ApiMailAdapter._validateTemplate (E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\ApiMailAdapter.js:601:22)
at new ApiMailAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\ApiMailAdapter.js:83:13)
at loadAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Adapters\AdapterLoader.js:35:16)
at loadAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Adapters\AdapterLoader.js:48:12)
at loadAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Adapters\AdapterLoader.js:50:12)
at getUserController (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Controllers\index.js:169:65)
at Object.getControllers (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Controllers\index.js:81:26)
at new ParseServer (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\ParseServer.js:110:40)
at new _ParseServer (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\index.js:92:18)
[nodemon] app crashed - waiting for file changes before starting...
`

Expected Outcome

[nodemon] startingnode server.jsinfo - Loaded env from E:\tiavina-mika\portfolio-v3\.env.local info - Using webpack 5. Reason: Enabled by default https://nextjs.org/docs/messages/webpack5 info - Using external babel configuration from E:\tiavina-mika\portfolio-v3\.babelrc (node:13856) DeprecationWarning: Listening to events on the Db class has been deprecated and will be removed in the next major version. (Usenode --trace-deprecation ...to show where the warning was created) event - compiled successfully Notre serveur tourne en mode development sur http://localhost:3001 event - build page: /api/parse/[...id] wait - compiling... event - compiled successfully

Environment

Node: 14.15.4
Npm: 7.20.1
"next": "11.1.2"

  • API Mail Adapter version: 2.1.0
  • Parse Server version: 4.10.3

Logs

E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\ApiMailAdapter.js:601
throw Errors.Error.templateContentPathInvalid;
^

Error: ApiMailAdapter: template content path is invalid.
at Function.get (E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\Errors.js:62:37)
at ApiMailAdapter._validateTemplate (E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\ApiMailAdapter.js:601:22)
at new ApiMailAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server-api-mail-adapter\lib\ApiMailAdapter.js:83:13)
at loadAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Adapters\AdapterLoader.js:35:16)
at loadAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Adapters\AdapterLoader.js:48:12)
at loadAdapter (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Adapters\AdapterLoader.js:50:12)
at getUserController (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Controllers\index.js:169:65)
at Object.getControllers (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\Controllers\index.js:81:26)
at new ParseServer (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\ParseServer.js:110:40)
at new _ParseServer (E:\tiavina-mika\portfolio-v3\node_modules\parse-server\lib\index.js:92:18)
[nodemon] app crashed - waiting for file changes before starting...

apiPayloadConverter doesn't have the awsSes method

New Issue Checklist

Issue Description

The adapter uses the ApiPayloadConverter.awsSes(payload) method in the apiCallback function, which gives the ApiPayloadConverter.awsSes is not a function error. After inspecting the ApiPayloadConverter.js in the src folder I saw that it has only the mailgun method. So either the awsSes method should be added or the documentation should be corrected.

Steps to reproduce

Actual Outcome

Expected Outcome

I expected the module to work with AWS SES

Failing Test Case / Pull Request

Environment

  • API Mail Adapter version: 2.1.0
  • Parse Server version: 5.3.3

Logs

Support users use their email as their username

New Issue Checklist

Issue Description

Parse-server supports "users use their email as their username" :

On the resetting passwords section of parse-server JS SDK document,

This will attempt to match the given email with the user’s email or username field, and will send them a password reset email. By doing this, you can opt to have users use their email as their username, or you can collect it separately and store it in the email field.

On the signing up section,

You are free to use an email address as the username. Simply ask your users to enter their email, but fill it in the username property — Parse.User will work as normal. We’ll go over how this is handled in the reset password section.

Email adapter have to handle username as an email in this case.
When the adapter got there user object as recipient and email filed of user is empty, use username as an email.

Parse-server check below code of parse-server:

If you want check the early discussion of this issue, please check this

Steps to reproduce

  • Setup parse-server with this email adapter.
  • Sing up : use their email as their username
  • Request password reset
Parse.User.requestPasswordReset("[email protected]")

Actual Outcome

You can't not get any email.

Expected Outcome

You can get an "reset password email".

Failing Test Case / Pull Request

#54

Environment

  • API Mail Adapter version: 2.10
  • Parse Server version: 4.10.4

Logs

Send email in Cloud Code requires template

New Issue Checklist

Issue Description

Sending an email in Cloud Code via Parse.Cloud.sendEmail() currently only works using an email template. It does not work with specifying the email content via parameters subject, text, html directly.

Steps to reproduce

Parse.Cloud.sendEmail({
  sender: config.sender,
  recipient: '[email protected]',
  subject: 'ExampleSubject',
  text: 'ExampleText',
  html: 'ExampleHtml',
});

Actual Outcome

Email sending fails throwing an error that no template is specified.

Expected Outcome

Email should send without template using the specified parameters.

Failing Test Case / Pull Request

#26

Environment

  • API Mail Adapter version: 1.0.5
  • Parse Server version: 4.5.0

Logs

(none)

SES Provider

New Feature / Enhancement Checklist

Current Limitation

I love the design of this module. Because of the smart design, running a custom provider is pretty easy, but I was wondering if you would like an SES converter? I've already built it and updated docs and ready to do a PR.

Feature / Enhancement Description

Simply adding an SES Payload Converter, with additions to docs to explain useage.

Example Use Case

Sending system emails via AWS SES.

Alternatives / Workarounds

The custom api support it totaly viable, so this is not strictly necessary, I just thought it might be nice to bake it into the package, but that could create additional noise, so I'm totally happy if you shut this down :D

3rd Party References

No really applicable, I don't think?

localeCallback add access to request

New Feature / Enhancement Checklist

Current Limitation

Currently choosing localization template requires writing user's locale to the user table and then querying it before sending the email. This is done in the localeCallback. However, this requires 1 read operation each time the email is dispatched. In addition, this doesn't allow for automatic locale detection. And if user changes browser language, they will still be getting their emails in their old language.

Feature / Enhancement Description

Would it be possible to provide access to request object inside the localeCallback? The request object of cloud functions usually contains the Allow-Language header, or cf-ipcountry header for the sites behind cloudflare.

These can be conveniently used for dynamic localization without any need to write or read anything from db.

Example Use Case

    localeCallback: async (req) => {
      const locale = req?.headers["accept-language"]?.split(",")?.[0]?.split("-")?.[0]; // en or tr or es
      return locale;
    },

Alternatives / Workarounds

3rd Party References

Allow placeholders to be used in password reset email and verification email

New Feature / Enhancement Checklist

Current Limitation

Sending a verification email and requesting a password reset email currently allows only username, appName, and link variables expansion to be used in a template. Whereas custom emails defined via this adapter allow specification of placeholders to contain potentially other variables that can be used in the templates. Examples include hero image url, app homepage, etc.

Feature / Enhancement Description

Please allow placeholders and/or placeholderCallback to be specified and used also for passwordResetEmail and verificationEmail templates.

Things to Consider

Looks like this change needs to be coordinated with parse-server UserController.js which hard codes the parameters that are passed into mail adapter.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.