CORS error with Netlify function

Hi,

I hope someone can help me, it would be much appreciated. I tried looking for other solutions already posted but nothing seemed to work.

I have been trying out Netlify functions and following this tutorial (using VueJS and Mailgun): Using serverless functions with Nuxt.js - LogRocket Blog

If I run on the CLI
netlify functions:invoke mail --no-identity --payload '{"email": "my@email.com"}' an email arrives okay! However, when I try and submit it via the browser displays a CORS error when in production, yarn dev using yarn netlify dev.

App: https://hungry-hamilton-94675d.netlify.app/

Access to XMLHttpRequest at 'http://localhost:3000/.netlify/functions/mail' from origin 'http://localhost:8888' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
index.vue?6ced:64 error Error: Network Error
    at createError (createError.js?2d83:16)
    at XMLHttpRequest.handleError (xhr.js?b50d:84)
xhr.js?b50d:177 POST http://localhost:3000/.netlify/functions/mail net::ERR_FAILED

mail.js:

require('dotenv').config()
const { MG_API_KEY, MG_DOMAIN, MG_HOST } = process.env
var mailgun = require('mailgun-js')({ apiKey: MG_API_KEY, domain: MG_DOMAIN, url: MG_HOST })

exports.handler = async (event) => {
  if (event.httpMethod !== 'POST') {
    return {
      statusCode: 405,
      body: 'Method Not Allowed',
      headers: { 'Allow': 'POST' }
    }
  }

  const data = JSON.parse(event.body)

  if (!data.email) {
    return { statusCode: 422, body: 'Email is required' }
  }

  const mailgunData = {
    from: 'jhome@email.com',
    to: 'jhome@email.com',
    subject: `New mail from`,
    html: `
    <h4> Email ${data.email} </h4>
    `
  }

  try {
    await mailgun.messages().send(mailgunData)

    return {
      statusCode: 200,
      body: 'Your message was sent successfully!',
    }
  } catch (error) {
      return {
        statusCode: 422,
        body: `Error: ${error}`
      }
  }
}

index.vue:

<template>
  <div class="container">
    <form @submit.prevent="sendFormLambda">
      <h3 class="text-lg leading-6 font-medium text-gray-900">Test inputs</h3>
      <p class="mt-1 text-sm text-gray-500">
        This is a test form. Please input any text.
      </p>
      <div>
        <label for="email" class="block text-sm font-medium text-gray-700"
          >Email</label
        >
        <div class="mt-1">
          <input
            v-model="form.email"
            type="text"
            name="email"
            id="email"
            class="p-2 focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 border rounded-md"
            placeholder="you@example.com"
          />
        </div>
      </div>
      <div class="pt-5">
        <div class="flex justify-end">
          <button
            type="button"
            class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
          >
            Cancel
          </button>
          <button
            type="submit"
            class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
          >
            Save
          </button>
        </div>
      </div>
    </form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      form: {
        email: '',
      },
    }
  },
  methods: {
    async sendFormLambda() {
      try {
        const response = await this.$axios.$post(
          '/.netlify/functions/mail',
          {
            email: this.form.email,
          }
        )
        
        console.log('success')
        this.form.email = ''
      } catch (error) {
        console.log('error', error)
      }
    },
  },
}
</script>

<style>
.container {
  @apply mx-auto;
  @apply max-w-screen-md;
}

body {
  font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  color: #35495e;
}
</style>

Hi there, @jhome :wave:

Welcome to the Netlify Forums :netliconfetti: It looks like this thread has been a bit quiet since you reached out-- thanks for your patience and for writing such a detailed post! We have been a bit underwater these past few weeks, but we haven’t forgotten you reached out.

Are you still encountering this error? If you are, what additional debugging steps have you taken since you last reached out?

If you are still having issues and would like us to dig in further, please provide your Netlify site name and function name.

Thanks!

1 Like

Hi Hilary,

Thanks so much for the reply. I haven’t actually managed to work on it since writing the thread, however, my site is https://hungry-hamilton-94675d.netlify.app/ and the function is called mail. I would like to do more debugging but have been incredibly busy. :frowning:

I would provide access to the repo but I can’t until next week.

Hey there, @jhome :wave:

That is alright, just send over the repo when you get a chance this week and then we will dive into this further. I’ll stay tuned for a response :slight_smile:

Hey @jhome,

I would suggest adding the header as part of your function’s response directly. Given your function is async, you can try something like:

return {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin": "*", // Allow from anywhere 
        },
        body: JSON.stringify(response)
    }

Note that if you are limiting https methods (for example, only GET methods are allowed), you’ll still need to make sure your function returns that Access-Control-Allow-Origin header for OPTION method requests which all browsers will do regardless of what method you use.

Let me know if that helps.

1 Like

Thanks @Scott and @hilary.

I added the headers in the function’s response directly like a true copy and paste programmer. I will read up more on HTTP methods.

Here’s the repo: https://github.com/jrah/form-netlify/blob/master/functions/mail/mail.js#L34:L36

https://hungry-hamilton-94675d.netlify.app/

Unfortunately it still seems to error out. :thinking:

When I access the function directly via the browser:

https://hungry-hamilton-94675d.netlify.app/.netlify/functions/mail Method Not Allowed

Looks like the function is still being called from localhost!

XMLHttpRequest cannot load http://localhost:3000/.netlify/functions/mail due to access control checks.

Perhaps you want to revise this?

1 Like

I am such a numpty! Working great now. Thanks!

1 Like

Glad it is working for you, @jhome :netliconfetti: @Scott, thanks for sharing these solutions,

2 Likes