How to send an email from JavaScript

You can't send an email directly with javascript.

You can, however, open the user's mail client:

window.open('mailto:[email protected]');

There are also some parameters to pre-fill the subject and the body:

window.open('mailto:[email protected]?subject=subject&body=body');

Another solution would be to do an ajax call to your server, so that the server sends the email. Be careful not to allow anyone to send any email through your server.


Indirect via Your Server - Calling 3rd Party API - secure and recommended


Your server can call the 3rd Party API. The API Keys are not exposed to client.

node.js

const axios = require('axios');

async function sendEmail(name, email, subject, message) {
  const data = JSON.stringify({
    "Messages": [{
      "From": {"Email": "<YOUR EMAIL>", "Name": "<YOUR NAME>"},
      "To": [{"Email": email, "Name": name}],
      "Subject": subject,
      "TextPart": message
    }]
  });

  const config = {
    method: 'post',
    url: 'https://api.mailjet.com/v3.1/send',
    data: data,
    headers: {'Content-Type': 'application/json'},
    auth: {username: '<API Key>', password: '<Secret Key>'},
  };

  return axios(config)
    .then(function (response) {
      console.log(JSON.stringify(response.data));
    })
    .catch(function (error) {
      console.log(error);
    });

}

// define your own email api which points to your server.
app.post('/api/sendemail/', function (req, res) {
  const {name, email, subject, message} = req.body;
  //implement your spam protection or checks.
  sendEmail(name, email, subject, message);
});

and then use use fetch on client side to call your email API. Use from email which you used to register on Mailjet. You can authenticate more addresses too. Mailjet offers a generous free tier.


Directly From Client - Calling 3rd Party API - not recomended


Send an email using only JavaScript

in short:

  1. register for Mailjet to get an API key and Secret
  2. use fetch to call API to send an email

Like this -

function sendMail(name, email, subject, message) {
  const myHeaders = new Headers();
  myHeaders.append("Content-Type", "application/json");
  myHeaders.set('Authorization', 'Basic ' + base64.encode('<API Key>'+":" +'<Secret Key>'));

  const data = JSON.stringify({
    "Messages": [{
      "From": {"Email": "<YOUR EMAIL>", "Name": "<YOUR NAME>"},
      "To": [{"Email": email, "Name": name}],
      "Subject": subject,
      "TextPart": message
    }]
  });

  const requestOptions = {
    method: 'POST',
    headers: myHeaders,
    body: data,
  };

  fetch("https://api.mailjet.com/v3.1/send", requestOptions)
    .then(response => response.text())
    .then(result => console.log(result))
    .catch(error => console.log('error', error));
}

Note: Keep in mind that your API key is visible to anyone, so any malicious user may use your key to send out emails that can eat up your quota.


I couldn't find an answer that really satisfied the original question.

  • Mandrill is not desirable due to it's new pricing policy, plus it required a backend service if you wanted to keep your credentials safe.
  • It's often preferable to hide your email so you don't end up on any lists (the mailto solution exposes this issue, and isn't convenient for most users).
  • It's a hassle to set up sendMail or require a backend at all just to send an email.

I put together a simple free service that allows you to make a standard HTTP POST request to send an email. It's called PostMail, and you can simply post a form, use JavaScript or jQuery. When you sign up, it provides you with code that you can copy & paste into your website. Here are some examples:

JavaScript:

<form id="javascript_form">
    <input type="text" name="subject" placeholder="Subject" />
    <textarea name="text" placeholder="Message"></textarea>
    <input type="submit" id="js_send" value="Send" />
</form>

<script>

    //update this with your js_form selector
    var form_id_js = "javascript_form";

    var data_js = {
        "access_token": "{your access token}" // sent after you sign up
    };

    function js_onSuccess() {
        // remove this to avoid redirect
        window.location = window.location.pathname + "?message=Email+Successfully+Sent%21&isError=0";
    }

    function js_onError(error) {
        // remove this to avoid redirect
        window.location = window.location.pathname + "?message=Email+could+not+be+sent.&isError=1";
    }

    var sendButton = document.getElementById("js_send");

    function js_send() {
        sendButton.value='Sending…';
        sendButton.disabled=true;
        var request = new XMLHttpRequest();
        request.onreadystatechange = function() {
            if (request.readyState == 4 && request.status == 200) {
                js_onSuccess();
            } else
            if(request.readyState == 4) {
                js_onError(request.response);
            }
        };

        var subject = document.querySelector("#" + form_id_js + " [name='subject']").value;
        var message = document.querySelector("#" + form_id_js + " [name='text']").value;
        data_js['subject'] = subject;
        data_js['text'] = message;
        var params = toParams(data_js);

        request.open("POST", "https://postmail.invotes.com/send", true);
        request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

        request.send(params);

        return false;
    }

    sendButton.onclick = js_send;

    function toParams(data_js) {
        var form_data = [];
        for ( var key in data_js ) {
            form_data.push(encodeURIComponent(key) + "=" + encodeURIComponent(data_js[key]));
        }

        return form_data.join("&");
    }

    var js_form = document.getElementById(form_id_js);
    js_form.addEventListener("submit", function (e) {
        e.preventDefault();
    });
</script>

jQuery:

<form id="jquery_form">
    <input type="text" name="subject" placeholder="Subject" />
    <textarea name="text" placeholder="Message" ></textarea>
    <input type="submit" name="send" value="Send" />
</form>

<script>

    //update this with your $form selector
    var form_id = "jquery_form";

    var data = {
        "access_token": "{your access token}" // sent after you sign up
    };

    function onSuccess() {
        // remove this to avoid redirect
        window.location = window.location.pathname + "?message=Email+Successfully+Sent%21&isError=0";
    }

    function onError(error) {
        // remove this to avoid redirect
        window.location = window.location.pathname + "?message=Email+could+not+be+sent.&isError=1";
    }

    var sendButton = $("#" + form_id + " [name='send']");

    function send() {
        sendButton.val('Sending…');
        sendButton.prop('disabled',true);

        var subject = $("#" + form_id + " [name='subject']").val();
        var message = $("#" + form_id + " [name='text']").val();
        data['subject'] = subject;
        data['text'] = message;

        $.post('https://postmail.invotes.com/send',
            data,
            onSuccess
        ).fail(onError);

        return false;
    }

    sendButton.on('click', send);

    var $form = $("#" + form_id);
    $form.submit(function( event ) {
        event.preventDefault();
    });
</script>

Again, in full disclosure, I created this service because I could not find a suitable answer.