parse-community / parse-server-api-mail-adapter

API Mail Adapter for Parse Server
MIT License
27 stars 18 forks source link

TypeError [ERR_INVALID_ARG_TYPE] when sending email #58

Closed ashish-naik closed 2 years ago

ashish-naik commented 2 years ago

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

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.

mtrezza commented 2 years ago

What you could try:

ashish-naik commented 2 years ago

i could run the demo by making below changes.

  1. Installed form-data, path, malign.js
  2. updated index.js to below to use filePath and use filePath in template option
'use strict';
const ApiMailAdapter = require('../src/ApiMailAdapter');
const ApiPayloadConverter = require('../src/ApiPayloadConverter');
const formData = require("form-data");
const Mailgun = require('mailgun.js');
const path = require('path');

const {
  key,
  domain,
  sender,
  recipient
} = require('./mailgun.json');

// Declare mail client
const mailgun = new Mailgun(formData);
const mailgunClient = mailgun.client({ username: "api", key });

// Configure mail client
const filePath = (file) => path.resolve(__dirname, '../spec/templates/', file);
console.log(filePath('password_reset_email_subject.txt'))
const config = {
  sender: sender,
  templates: {
    passwordResetEmail: {
      subjectPath: filePath('password_reset_email_subject.txt'),
      textPath: filePath('password_reset_email.txt'),
      htmlPath: filePath('password_reset_email.html')
    },
    verificationEmail: {
      subjectPath: filePath('verification_email_subject.txt'),
      textPath: filePath('verification_email.txt'),
      htmlPath: filePath('verification_email.html')
    },
    customEmail: {
      subjectPath: filePath('custom_email_subject.txt'),
      textPath: filePath('custom_email.txt'),
      htmlPath: filePath('custom_email.html'),
      placeholders: {
        username: "DefaultUser",
        appName: "DefaultApp"
      },
      extra: {
        replyTo: 'no-reply@example.com'
      }
    }
  },
  apiCallback: async ({ payload }) => {
    const mailgunPayload = ApiPayloadConverter.mailgun(payload);
    await mailgunClient.messages.create(domain, mailgunPayload);
  }
};

const adapter = new ApiMailAdapter(config);

adapter.sendMail({
  templateName: 'customEmail',
  recipient: recipient,
  placeholders: {
    appName: "ExampleApp",
    username: "ExampleUser"
  },
  direct: true
});

made similar change to my local as well as heroku index.js but still getting error.

node:internal/validators:119
    throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
    ^
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
    at new NodeError (node:internal/errors:371:5)
    at validateString (node:internal/validators:119:11)
    at Object.resolve (node:path:1098:7)
    at filePath (/app/index.js:15:33)
    at Object.<anonymous> (/app/index.js:16:13)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
  code: 'ERR_INVALID_ARG_TYPE'

Below is local parse server index.js. console.log to print generates same error.

var path = require('path');

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');
console.log("Before filePath")
const filePath = (file) => path.resolve(__dirname, './files/', file);
console.log(filePath('password_reset_email_subject.txt'))

var api = new ParseServer({
.... other options
  emailAdapter: {
    module: 'parse-server-api-mail-adapter',
    options: {
      sender: process.env.APP_SUPPORT_EMAIL,
      templates: {
        passwordResetEmail: {
            subjectPath: filePath('password_reset_email_subject.txt'),
            textPath: filePath('password_reset_email.txt'),
            htmlPath: filePath('password_reset_email.html')
        },
        verificationEmail: {
            subjectPath: filePath('verification_email_subject.txt'),
            textPath: filePath('verification_email.txt'),
            htmlPath: filePath('verification_email.html')
        },
      },
      apiCallback: async ({ payload, locale }) => {
        const mailgunPayload = ApiPayloadConverter.mailgun(payload);
        await mailgunClient.messages.create(mailgunDomain, mailgunPayload);
      }
    }
  }
});
mtrezza commented 2 years ago

The path.resolve([...paths]) method returns a string. If it returns undefined you would want to check the arguments you pass to it and why the path can't be resolved.

mtrezza commented 2 years ago

I'm closing this issue as it does not seem to be an issue of the API Mail Adapter.

ashish-naik commented 2 years ago

@mtrezza I could get it working.

I tried to understand your mail adaptor code but i am not good with javascript beyond basic so didn't understand eveything. But adding console statements at some places realised that code was trying to use _loadFile eventhough I was trying method without passing template. Not sure i am correct though.

So i created all the templates and added filePath in index.js and used it in template options.

Thanks. I like your adaptor especially the placeholder feature.