12

I couldn't find any way how can I set up CORS using serverless netlify functions. I have used this function example to create my own e-mail form sender:

const nodemailer = require('nodemailer');

exports.handler = function(event, context, callback) {
    let transporter = nodemailer.createTransport({
        host: 'smtp.gmail.com',
        port: 465,
        secure: true,
        auth: {
            type: 'OAuth2',
            user: process.env.MAIL_LOGIN,
            clientId: process.env.CLIENT_ID,
            clientSecret: process.env.CLIENT_SECRET,
            refreshToken: process.env.REFRESH_TOKEN,
            accessToken: process.env.ACCESS_TOKEN
        }
    });
    console.log(event.body);

    transporter.sendMail({
        from: process.env.MAIL_LOGIN,
        to: process.env.MAIL_TO,
        subject: process.env.SUBJECT + new Date().toLocaleString(),
        text: event.body
    }, function(error, info) {
        if (error) {
            callback(error);
        } else {
            callback(null, {
                statusCode: 200,
                body: "Ok"
            });
        }
    });
}

But unfortunately, I am able to send it through every single domain which is not really safe as some people can send spam into that inbox.

Would you be able to follow me to any example? Thank you in advance

user4572896
  • 131
  • 2
  • 7

3 Answers3

16

You can do something like this:

const headers = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'Content-Type',
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE'
};

if (event.httpMethod !== 'POST') {
    // To enable CORS
    return {
      statusCode: 200, // <-- Important!
      headers,
      body: 'This was not a POST request!'
    };
 }

Here is how I used it in a larger mapper function:

// src/customers.js
exports.handler = async (event, context) => {
  const path = event.path.replace(/\.netlify\/functions\/[^\/]+/, '');
  const segments = path.split('/').filter(e => e);

  switch (event.httpMethod) {
    case 'GET':
      // e.g. GET /.netlify/functions/customers
      if (segments.length === 0) {
        return require('./customers/read-all').handler(event, context);
      }
      // e.g. GET /.netlify/functions/customers/123456
      if (segments.length === 1) {
        event.id = segments[0];
        return require('./customers/read').handler(event, context);
      } else {
        return {
          statusCode: 500,
          body:
            'too many segments in GET request, must be either /.netlify/functions/customers or /.netlify/functions/customers/123456'
        };
      }
    case 'POST':
      // e.g. POST /.netlify/functions/customers with a body of key value pair objects, NOT strings
      return require('./customers/create').handler(event, context);
    case 'PUT':
      // e.g. PUT /.netlify/functions/customers/123456 with a body of key value pair objects, NOT strings
      if (segments.length === 1) {
        event.id = segments[0];
        console.log(event.id);
        return require('./customers/update').handler(event, context);
      } else {
        return {
          statusCode: 500,
          body:
            'invalid segments in POST request, must be /.netlify/functions/customers/123456'
        };
      }
    case 'DELETE':
      // e.g. DELETE /.netlify/functions/customers/123456
      if (segments.length === 1) {
        event.id = segments[0];
        return require('./customers/delete').handler(event, context);
      } else {
        return {
          statusCode: 500,
          body:
            'invalid segments in DELETE request, must be /.netlify/functions/customers/123456'
        };
      }
    case 'OPTIONS':
      // To enable CORS
      const headers = {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': 'Content-Type',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE'
      };
      return {
        statusCode: 200, // <-- Must be 200 otherwise pre-flight call fails
        headers,
        body: 'This was a preflight call!'
      };
  }
  return {
    statusCode: 500,
    body: 'unrecognized HTTP Method, must be one of GET/POST/PUT/DELETE/OPTIONS'
  };
};

I wrote a tutorial about how to work build serverless databases & netlify functions where I had CORS enabled, you can find the article here.

ahmaman
  • 181
  • 1
  • 3
  • Very interesting how the error response for not a post needs to stay 200. That was definitely my issue. – blindguy Oct 28 '21 at 01:48
4
    exports.handler = async (event, context) => {
    return {
      statusCode: 200,
      headers: {
        /* Required for CORS support to work */
        'Access-Control-Allow-Origin': '*',
        /* Required for cookies, authorization headers with HTTPS */
        'Access-Control-Allow-Credentials': true
      },
      body: JSON.stringify({
        message: 'Hello from netlify',
        event: event,
      })
    }
  }
Viraj Singh
  • 1,951
  • 1
  • 17
  • 27
0

You can also use express with cors. It's a way better dynamic handling of cors options.

I extracted my own netlify configuration from my projects and pushed it to GitHub:

https://github.com/kevludwig/netlify-functions-express

There is also an example sending mails using nodemailer.