mailgun.js icon indicating copy to clipboard operation
mailgun.js copied to clipboard

Fails in cloudflare-workers environment

Open nosovk opened this issue 2 years ago • 10 comments

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 avatar Jan 24 '23 16:01 nosovk

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
});

nosovk avatar Jan 24 '23 16:01 nosovk

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
		}

leviwheatcroft avatar Feb 03 '23 22:02 leviwheatcroft

@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', '[email protected]');
			body.append('to', '[email protected]');
			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)

nosovk avatar Feb 03 '23 23:02 nosovk

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.

leviwheatcroft avatar Feb 04 '23 01:02 leviwheatcroft

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

nosovk avatar Feb 04 '23 20:02 nosovk

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

allenfuller avatar Mar 01 '23 17:03 allenfuller

Same here, running a remix app on cloudflare workers.

Knaackee avatar Dec 04 '23 10:12 Knaackee

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

nosovk avatar Dec 04 '23 11:12 nosovk

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

whoislewys avatar Mar 06 '24 11:03 whoislewys

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.

nosovk avatar Mar 06 '24 13:03 nosovk