CORS and browser requests
Why the usend API cannot be called from the browser, and what to do instead.
You may see an error like "blocked by CORS policy" when you call https://api.usend.et from JavaScript in a web page. This is by design.
Why it is blocked
The API only answers cross-origin browser requests for the usend dashboard. Your website's origin is not allowed, so the browser refuses to expose the response, and the preflight request fails.
Even if it were allowed, it would be a mistake: calling the API from a browser means putting your API key in the page. Anyone who opens the developer tools can copy it and send mail as you. See Handling API keys.
What to do instead
Send from a server you control and let the browser call that:
browser --> your server / function --> usend API
(no key) (API key in a secret)Your server can be a route in your framework (Next.js, Remix, SvelteKit), a serverless function (Vercel, Cloudflare Workers, Lambda) or any backend.
A minimal proxy
// POST /api/contact from your own page
export async function POST(req: Request) {
const { email, message } = await req.json();
if (!email || !message || message.length > 5000) return new Response('Bad request', { status: 400 });
const res = await fetch('https://api.usend.et/emails', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.USEND_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
from: 'Acme <[email protected]>', // fixed, never taken from the request
to: ['[email protected]'], // fixed
reply_to: email,
subject: 'Contact form',
text: message,
}),
});
return new Response(null, { status: res.ok ? 204 : 502 });
}Your own endpoint should:
- Fix the
fromandtoaddresses yourself, so it cannot be used as an open mail relay. - Limit the size of the message and the rate per visitor (and add a CAPTCHA if the form is public).
- Check the caller is allowed (a session, a signed token).
Server to server
Calls from a backend do not involve CORS at all: CORS is a browser rule. If you see a CORS error, your code is running in the browser.
Do not work around it
Do not try to disable CORS with a public proxy or a "no-cors" mode. A no-cors request cannot send the Authorization header or JSON body. A public CORS proxy would see your key.