mailgun / mailgun.js

Javascript SDK for Mailgun
https://www.npmjs.com/package/mailgun.js
Apache License 2.0
519 stars 110 forks source link

Fails in cloudflare-workers environment #341

Open nosovk opened 1 year ago

nosovk commented 1 year ago

When I try to use mailgun.js in Cloudflare worker it fails with error:

define is not defined

Full trace: "ReferenceError: define is not defined\n at node_modules/mailgun.js/mailgun.web.js (worker.mjs:2093:5)\n at __require (worker.mjs:12:50)\n at .svelte-kit/output/server/entries/pages/contactus/_page.server.js (worker.mjs:5109:30)\n at __init (worker.mjs:9:56)\n at .svelte-kit/output/server/nodes/4.js (worker.mjs:5200:5)\n at __init (worker.mjs:9:56)\n at worker.mjs:7931:43\n at async Promise.all (index 1)\n at async respond (worker.mjs:7691:23)\n at async Object.fetch (worker.mjs:8035:15)"

Related issues: 1, 2, 3

nosovk commented 1 year ago

Minimal code reproduction:

import formData from 'form-data';
import Mailgun from 'mailgun.js';

import { MAILGUN_API_KEY } from '$env/static/private';

const mailgun = new Mailgun(formData);
const mg = mailgun.client({
    username: 'api',
    url: 'https://api.mailgun.net',
    key: MAILGUN_API_KEY
});
leviwheatcroft commented 1 year ago

Not a solution, but for others wanting to implement a simple send fn using a native request this might save some time...

You need to define the env keys, and the message param should be an object containing from, to, subject, and text

        async function mailgunSend (message) {
            const {
                MAILGUN_API_KEY,
                MAILGUN_BASE_URL,
                MAILGUN_DOMAIN
            } = env
            const body = new FormData()
            Object.entries(message).forEach(([key, value]) => body.append(key, value))
            const request = new Request(
                `${MAILGUN_BASE_URL}/v3/${MAILGUN_DOMAIN}/messages`,
                {
                    method: 'POST',
                    headers: {
                        'Authorization': `Basic ${btoa(`api:${MAILGUN_API_KEY}`)}`,
                    },
                    body
                }
            )
            const response = await fetch(request)
            return response
        }
nosovk commented 1 year ago

@leviwheatcroft thanks, I came to that solution also. But I use cloudflare workers, and there is no FormData there (node 18 not available now). That's why I make some check, and found that you can do the same without FormData. Mailgun supports application/x-www-form-urlencoded If you don't need to send attachments you can write something like that:

const body = new URLSearchParams();
body.append('from', 'from@mail.com');
            body.append('to', 'to@mail.com');
            body.append('subject', 'mail from site');
            body.append('html', `<h1>my mail</h1>`);
const res = await fetch(`https://api.mailgun.net/v3/${mg.domain}/messages`, {
                method: 'POST',
                body: body.toString(),
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    Authorization: authorization
                }
            });
const json = await res.json();

if (res.status !== 200) {
    return fail(500, { success: false, error: json.message ?? 'unknown mail api error' });
}

this will actually work without additional dependencies in NodeJS<18. (in 18 there is native FormData implementation)

leviwheatcroft commented 1 year ago

I'm using cloudflare workers also, but completely new, haven't tried this in production yet.

FormData is working in the wrangler development environment. It doesn't work in production? I had thought cloudflare workers had a browser-like environment rather than node, which would have FormData.

nosovk commented 1 year ago

I use SvelteKit, and can't use workers with nodejs 17 version. SvelteKit works only with LTS versions, 16 or 18. It's possible that FormData works in NodeJS 17. But in NodeJS 16 in CloudFlare workers global FromData was not present, it was only in request object. That's why I found workaround with URLSearchParams

allenfuller commented 1 year ago

+1 running into this issue w/ Mailgun.js 8.1.0 in a Meteor.js app.

Knaackee commented 10 months ago

Same here, running a remix app on cloudflare workers.

nosovk commented 10 months ago

Same here, running a remix app on cloudflare workers.

you may use solution form https://github.com/mailgun/mailgun.js/issues/341#issuecomment-1416505938 it works for a year in different projects. But, unfortunately, it will not work if you want to send attachments. In my case I upload attachment to 3s, and then attach link to email

whoislewys commented 7 months ago

I need attachments, how would you do this with attachments? Link attachments sometimes get blocked by certain email clients

nosovk commented 7 months ago

It will not work with attachments, until you use FormData, that will correctly encode binary data. I've fixed that issue by uploading attachments to CloudFlare R2, and them just inserted links to them. Pretty strange solution, but it helped.