如何使用JavaScript发送电子邮件

328

我想让我的网站具备在不刷新页面的情况下发送电子邮件的能力。因此,我想使用JavaScript。

<form action="javascript:sendMail();" name="pmForm" id="pmForm" method="post">
Enter Friend's Email:
<input name="pmSubject" id="pmSubject" type="text" maxlength="64" style="width:98%;" />
<input name="pmSubmit" type="submit" value="Invite" />

这是我想调用函数的方式,但我不确定要在 JavaScript 函数中放什么。根据我的研究,我找到了一个使用“mailto”方法的示例,但我理解这并没有直接从网站发送。

所以我的问题是,在哪里可以找到在 JavaScript 函数内直接从网站发送电子邮件的内容。

function sendMail() {
    /* ...code here...    */
}

10
使用服务器端语言来实际发送电子邮件,使用 AJAX 来获得所需的外观和感觉。 - Shadow The Spring Wizard
4
可能有些晚了,但这个链接可能会帮到你:https://dev59.com/PXVC5IYBdhLWcg3whBaj - PatrickMelia
3
Gmail用户可以使用它,参见https://developers.google.com/gmail/api/。 - Dennis S
1
如下所述,您可能还希望查看EmailJS。它允许您直接从JavaScript中使用预构建的模板发送电子邮件,并支持动态参数、附件、验证码、REST API等功能。我们也提供了一个免费层次来入门 [披露 - 我是其中之一的创作者]。 - Sasha
1
请注意,如果您使用接受的答案,则电子邮件将来自用户的帐户。要从您的个人或业务帐户发送电子邮件,正确的方法是使用JavaScript通过您自己的服务器或第三方服务(例如Byteline)发送电子邮件。更多详细信息请参见下面的答案 - dsbajna
20个回答

392

你不能直接使用JavaScript发送电子邮件。

但是,你可以打开用户的邮件客户端:

window.open('mailto:test@example.com');

还有一些参数可以预先填写主题和正文:

window.open('mailto:test@example.com?subject=subject&body=body');
另一种解决方法是通过ajax调用您的服务器,以便服务器发送电子邮件。请注意不要允许任何人通过您的服务器发送电子邮件。

3
如果打开网页的程序已经具备电子邮件客户端功能(例如 Opera 12.50),则它会将链接作为常规URL打开。此外,Thunderbird也具有Firefox Gecko引擎:它可以通过电子邮件中的超链接打开网页并在新标签页中显示。 - user2284570
14
请注意,你也可以使用 window.location.href(就像这个答案中所示:https://dev59.com/PXVC5IYBdhLWcg3whBaj#271172)来打开邮件客户端,这样当用户完成邮件后不会留下空白窗口。 - igneosaur
2
subjectbody是变量还是实际将在字段中的文本? - lost_in_the_source
4
确实,那个回答并没有回答问题,但是@rahulroy的回答很好。 - Medet Tleukabiluly
9
我会更进一步,执行window.open( String( 'mailto:recipient^example.com' ).replace('^', '@') );来混淆垃圾邮件机器人。 - Pavel
显示剩余3条评论

108

通过您的服务器间接调用第三方API-安全且推荐


您的服务器可以调用第三方API。 API密钥不会暴露给客户端。

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

然后在客户端使用fetch调用您的电子邮件API。

使用from email,这是您在Mailjet上注册时使用的。您还可以验证更多地址。Mailjet提供慷慨的免费套餐


更新2023年:如评论中所指出,由于CORS,下面的方法不再起作用

如果要测试发送电子邮件,则这只有用处

直接从客户端 - 调用第三方API - 不建议


简而言之:

  1. 注册Mailjet以获取API密钥和密码
  2. 使用fetch调用API发送电子邮件

就像这样 -

function sendMail(name, email, subject, message) {
  const myHeaders = new Headers();
  myHeaders.append("Content-Type", "application/json");
  myHeaders.set('Authorization', 'Basic ' + btoa('<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));
}

sendMail('Test Name',"<YOUR EMAIL>",'Test Subject','Test Message')

注意:请记住您的API密钥对任何人都是可见的,因此任何恶意用户都可以使用您的密钥发送电子邮件以消耗您的配额。


12
虽然文章中已经提到了这一点,但我仍然觉得应该在这里再次强调:虽然这种方法有效,但会存在一些安全问题,因为您需要将 API 密钥发送给客户端。这可能会被滥用。 - cantdutchthis
1
由于 CORS 的限制,这个不再起作用了。 - Professor of programming

60

我找不到一个真正满意原问题的答案。

  • Mandrill由于其新的定价政策以及如果你想保护你的凭据,它需要后端服务,因此并不理想。
  • 通常最好隐藏你的电子邮件,这样你就不会出现在任何列表中(mailto方案暴露了这个问题,并且对大多数用户来说并不方便)。
  • 设置sendMail或需要后端来发送电子邮件都很麻烦。

我创建了一个简单的免费服务,可以通过发送标准的HTTP POST请求来发送电子邮件。它叫做PostMail,你可以简单地提交表单、使用JavaScript或jQuery。当你注册时,它会提供代码,你可以将其复制并粘贴到你的网站上。以下是一些示例:

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>

再次完全公开,我创建了这项服务是因为我找不到一个合适的答案。


2
这是最好的解决方案。非常感谢你。Mandrill不再有免费计划,而Mailgun不支持CORS,因此也不支持JavaScript。 - stallingOne
10
这个跟其他的有同样的问题吗?访问令牌(API密钥)被曝露了。 - Greg Ennis
3
他们每天的邮件发送限制为25封。 - Archi
1
现在应该已经恢复了。很抱歉! - user949286
1
请您在网站上添加隐私政策,说明一旦信息到达服务器后会发生什么。这是为了符合GDPR的要求。谢谢。 - Professor of programming
显示剩余12条评论

43

我知道我太晚回答这个问题了,但是无论如何,我认为这对于任何想通过JavaScript发送电子邮件的人都会有所帮助。

我建议的第一种方法是使用回调在服务器上处理此操作。如果您真的想要使用JavaScript来处理它,请按照以下建议操作。

我发现最简单的方法是使用smtpJs。这是一个免费的库,可用于发送电子邮件。

1.像下面这样包含脚本

<script src="https://smtpjs.com/v3/smtp.js"></script>

2. 您可以像这样发送电子邮件

Email.send({
    Host : "smtp.yourisp.com",
    Username : "username",
    Password : "password",
    To : 'them@website.com',
    From : "you@isp.com",
    Subject : "This is the subject",
    Body : "And this is the body"
    }).then(
      message => alert(message)
    );

这并不可取,因为它会在客户端上显示您的密码。因此,您可以采取以下措施:加密您的SMTP凭证,并将其锁定到单个域,并传递安全令牌而不是凭据。

Email.send({
    SecureToken : "C973D7AD-F097-4B95-91F4-40ABC5567812",
    To : 'them@website.com',
    From : "you@isp.com",
    Subject : "This is the subject",
    Body : "And this is the body"
}).then(
  message => alert(message)
);

如果您没有SMTP服务器,可以使用诸如 Elastic Email 等smtp中继服务。

此外,这是官方 SmtpJS.com网站 的链接,您可以在此找到所需的所有示例以及创建安全令牌的地方。

希望有人会发现这些详细信息实用。祝您编码愉快。


9
这仍然意味着将您的 SMTP 服务器完全授权给第三方,以便他们可以代表您中转邮件,作为交换,他们得到了什么? - Quentin
1
SecureToken只有在创建时指定的域名才有效,因此从另一个域调用js将无法生效。 - smoore4
4
@smoore4 没错,但他们仍然需要在他们的服务器上解密它并访问您的密码和其他信息。我不会相信这项服务。 - Konrad
1
最安全且唯一的方式是托管您自己的服务。 - Konrad
2
错误 Uncaught ReferenceError: Email is not defined 是否是预期的?我相信您没有定义 Email。还是说您使用了代码片段而不是代码围栏,我们不应该运行它?此外,我认为您并不太晚。 - BarryCap
@BarryCap您可以连接您的域名/电子邮件 - 如果您没有域名的话 -
  1. 前往以下网址: https://app.elasticemail.com/marketing
  2. 点击“验证域名”。
  3. 选择“我没有拥有一个域名”。
- Joseph Ali

26

您可以在此帖子中找到应放置在JavaScript函数内部的内容。

function getAjax() {
    try {
        if (window.XMLHttpRequest) {
            return new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            try {
                return new ActiveXObject('Msxml2.XMLHTTP');
            } catch (try_again) {
                return new ActiveXObject('Microsoft.XMLHTTP');
            }
        }
    } catch (fail) {
        return null;
    }
}

function sendMail(to, subject) {
     var rq = getAjax();

     if (rq) {
         // Success; attempt to use an Ajax request to a PHP script to send the e-mail
         try {
             rq.open('GET', 'sendmail.php?to=' + encodeURIComponent(to) + '&subject=' + encodeURIComponent(subject) + '&d=' + new Date().getTime().toString(), true);

             rq.onreadystatechange = function () {
                 if (this.readyState === 4) {
                     if (this.status >= 400) {
                         // The request failed; fall back to e-mail client
                         window.open('mailto:' + to + '?subject=' + encodeURIComponent(subject));
                     }
                 }
             };

             rq.send(null);
         } catch (fail) {
             // Failed to open the request; fall back to e-mail client
             window.open('mailto:' + to + '?subject=' + encodeURIComponent(subject));
         }
     } else {
         // Failed to create the request; fall back to e-mail client
         window.open('mailto:' + to + '?subject=' + encodeURIComponent(subject));
     }
}

提供您自己的PHP(或任何语言)脚本发送电子邮件。


23

我要向你透露一个消息。你不能单纯地使用 JavaScript 发送电子邮件。


根据 OP 提出的问题,我的答案并不准确,正如 @KennyEvitt 在评论中所指出的那样。看起来你可以使用 JavaScript 作为 SMTP 客户端

然而,我没有深入挖掘它是否足够安全和跨浏览器兼容。因此,我既不能鼓励也不能阻止你使用它。请自行决定使用风险。


1
可以使用Ajax甚至隐藏的iframe来完成...你永远不知道。 - Zebra
1
@danialentzri:JavaScript永远不会成为邮件中继,这就是我所说的“per se”的意思。 - Shef
糟糕!说实话,我的显示器很小,不支持滚动条。 - Zebra
从我快速浏览看来,@KennyEvitt似乎仍需要一个邮件继电器。这基本上是我在回答中所说的。 - Shef
@Shef,你快速浏览了一下,看到了什么?我找不到任何其他电子邮件客户端所需的要求。或者你是在声称,例如Microsoft Outlook也无法发送电子邮件吗?从技术上讲,这有点正确,但不是我希望其他人理解的意义上。 - Kenny Evitt

14

似乎有一个新的解决方案出现在视野中。它被称为EmailJS。他们声称不需要服务器代码,您可以请求邀请。

更新于2016年8月:EmailJS似乎已经上线了。您可以免费发送每月最多200封电子邮件,并提供更高容量的订阅服务。


这有些误导人,UI非常漂亮但几乎没有文档示例或帮助。建议回避。 - Skarsnik
我尝试使用emailJS,但它只能发送到我的电子邮件。如何将邮件发送到其他任何的邮箱? - Maged Saeed
4
虽然有些晚了,但是在电子邮件模板部分,当编辑一个模板时,你可以指定“收件人”的电子邮件地址。你甚至可以使用他们的模板选项将“收件人”字段设置为动态。他们的文档详细介绍了这一点。 - abagh0703
1
刚刚将EmailJS集成到我的React应用程序中。它运行良好,安装过程也相当顺利。邮件直接发送到我想要的邮箱。请确保添加reCAPTCHA。谢谢! - digiwand

7

如上所示,window.open('mailto:test@example.com');并不能防止垃圾邮件机器人收集"test@example.com"电子邮件地址。我过去常常遇到这个问题。

var recipient="test";
var at = String.fromCharCode(64);
var dotcom="example.com";
var mail="mailto:";
window.open(mail+recipient+at+dotcom);

5
在您的sendMail()函数中,添加一个ajax调用到您的后端,在那里您可以在服务器端实现此功能。

3

Javascript是客户端语言,你不能用Javascript发送电子邮件。浏览器只能识别mailto:,并启动默认的邮件客户端。


这就解释了为什么我找不到任何相关信息。谢谢! - user906357
同样的事情...未来的API可能允许原始连接到端口... - user2284570
这是最准确的答案!其他使其听起来可能的答案,都在使用后端.. OP说仅限Javascript。意思是,请勿使用后端,即使是SAAS后端。好答案。 - Dan Chase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接