使用 Sendgrid/Nodemailer 将 Angular 表单数据发布到 Node.js

Posted

技术标签:

【中文标题】使用 Sendgrid/Nodemailer 将 Angular 表单数据发布到 Node.js【英文标题】:Post Angular form data to Node.js with Sendgrid/Nodemailer 【发布时间】:2015-11-28 00:33:02 【问题描述】:

我已关注this example 将数据从我的 Angular 应用程序发布到 Node.js,以将网络表单发布到 Sendgrid。经过一些更改后,这可以正常工作,非常感谢您的快速入门。正在将我的表单数据发布到 Sendgrid!

对于这个项目,我使用Angular Fullstack 能够在我的 Angular 应用程序中使用 Node 功能。

但是,此示例只有输入字段和文本区域。我希望能够添加一个文件(PDF、Docx 等),以便人们可以通过 Sendgrid 向收件人发送附件。我已经搜索了一个解决方案,但找不到一个可行的例子。也许是因为我想要实现的目标是不可能的。

我的观点(客户):

<div ng-controller="ContactFormCtrl" id="contactformbox" style="margin-top:50px;" class="mainbox" >                    
  <div class="panel panel-info" >

          <div class="panel-heading">
              <div class="panel-title">Solliciteer direct</div>
          </div>     

          <div style="padding-top:30px" class="panel-body" >
              <form id="loginform" class="form-horizontal" role="form" name="contactform">

                  <div style="margin-bottom: 25px" class="input-group">
                    <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
                    <input type="email" name="to" ng-model="email.to" ng-required="true" id="email-to" class="form-control" name="username" value="" placeholder="The emailadres from the employer">       
                  </div>

                  <div style="margin-bottom: 25px" class="input-group">
                      <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
                      <input type="email" name="from" ng-model="email.from" ng-required="true" id="email-from" class="form-control" name="email-from" placeholder="Your e-mail address">
                  </div>

                  <div style="margin-bottom: 25px" class="input-group">
                      <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
                      <input type="text" name="subject" ng-model="email.subject" ng-required="true" id="email-subject" class="form-control" name="subject" placeholder="Your subject please">
                  </div>

                  <div style="margin-bottom: 25px" class="input-group">
                      <input type="file" name="file" ng-model="email.file" ng-required="true" id="email-file" class="form-control" name="file">
                  </div>

                  <div style="margin-bottom: 25px" class="input-group">
                    <textarea ng-model="email.text" name="text" placeholder="Enter Text Here.." class="form-control" rows="5" id="comment"></textarea>
                  </div>    

                  <div style="margin-top:10px" class="form-group">
                      <!-- Button -->
                      <div class="col-sm-12 controls">
                            <button id="emailSubmitBn" class="btn btn-success" type="submit" ng-click="submitEmail()">Submit</button>
                      </div>
                  </div>
              </form>     
        </div>                     
  </div>  

我的控制者(客户):

angular.module('angularMyApp')
.controller('ContactFormCtrl', function ($scope, $http) 
  $scope.submitEmail = function() 

    console.log("TEST");
    //Request
    $http.post('/api/email', $scope.email) 
    .success(function(data, status) 
        console.log("Sent ok");
    )
    .error(function(data, status) 
        console.log("Error");
    )
  ;
);

我的 APP.JS(服务器):

'use strict';

// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';

var express = require('express');
var config = require('./config/environment');
var http = require('http');
var bodyParser = require('body-parser');

var options = 
    auth: 
        api_key: process.env.SENDGRID_APIKEY; 
    


var nodemailer = require('nodemailer');
var sgTransport = require('nodemailer-sendgrid-transport');

// Setup server
var app = express();
var server = require('http').createServer(app);
require('./config/express')(app);
require('./routes')(app);

var mailer = nodemailer.createTransport(sgTransport(options));

app.post('/api/email', function(req, res) 
var mailOptions = 
    to: ['test@test.nl', req.body.to],
    from: req.body.from,
    subject: req.body.subject,
    text: req.body.text
;

mailer.sendMail(mailOptions, function(err, res) 
    if (err)  
        console.log(err) 
    
    console.log(res);
  );
);

// Start server
server.listen(config.port, config.ip, function () 
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
);

// Expose app
exports = module.exports = app;

有两个主要问题:

    客户端:如何在此表单中将附件从 Angular 发布到节点?我必须先上传文件还是可以使用 $http.post 将其发送到 Node?还是我必须使用 ng-file-upload? 服务器端:如何将附件发送到 Sendgrid/Nodemailer。将服务器上的 app.js 中的硬编码文件发送到 Sendgrid 不起作用。邮件已成功发送到 Sendgrid,但不包含附件。

非常感谢!

【问题讨论】:

同时我在github.com/BrentAureli/BrentAureli.com/tree/…找到了一些信息。但是按照这个确切的例子,让我发布数据但仍然有错误。 server.js 中的 multer 代码不起作用,因为 multer 有一个更新的库。具有“文件”属性的输入字段不能附加到 ng-model。您必须为此使用自定义指令。这里有什么想法吗? 【参考方案1】:

感谢 gilly3,我终于完成了工作。我不得不对他的代码做一点小改动。在我更改的控制器中:

formData.set(key, $scope.email[key]);

转至以下代码:

formData.append(key, $scope.email[key]);

【讨论】:

【参考方案2】:

1。上传带有角度形式的文件

您遇到的第一个问题是ng-model 不适用于&lt;input type="file" /&gt;。因此,您需要创建一个自定义指令来使用文件填充模型。

.directive('fileModel', ['$parse', function ($parse) 
    return 
        restrict: 'A',
        link: function(scope, element, attrs) 
            var model = $parse(attrs.fileModel);
            var modelSetter = model.assign;

            element.bind('change', function()
                scope.$apply(function()
                    modelSetter(scope, element[0].files[0]);
                );
            );
        
    ;
]);

然后像这样在文件输入元素上使用指令:

<input type="file" file-model="email.attachment" ng-required="true" id="email-attachment" name="attachment" class="form-control" />

请注意,我将 email.file 更改为 email.attachment 以避免其余代码混淆。

接下来,您需要将该文件包含在您的 AJAX 请求中。为此,您需要使用FormData。使用FormData.append()从范围填充它:

$scope.submitEmail = function() 
    var formData = new FormData();
    Object.keys($scope.email).forEach(function(key) 
        formData.append(key, $scope.email[key]);
    );
    $http.post('/api/email', formData, 
        transformRequest: angular.identity,
        headers: 'Content-Type': undefined
    ).then(function(data, status) 
        console.log("Sent ok");
    , function(data, status) 
        console.log("Error");
    );
;

请注意,我还向$http.post() 传递了一个配置对象。这是为了防止angular解析FormData对象并设置内容类型。

这部分答案我非常依赖this blog post。

2。使用 Nodemailer 发送附件

要在 express 中访问文件,请使用multer。

安装:

$ npm install --save multer

用法:

var multer = require('multer');
var upload = multer();

app.post('/api/email', upload.single('attachment'), function(req, res) 
    // req.file contains the 'attachment' file
    ...
);

从Nodemailer's Readme section on email fields 开始,它表示使用attachments 属性,该属性是attachment objects 的数组。

app.post('/api/email', upload.single('attachment'), function(req, res) 
    var mailOptions = 
        to: ['test@test.nl', req.body.to],
        from: req.body.from,
        subject: req.body.subject,
        text: req.body.text,
        attachments: [
            
                filename: req.file.originalname,
                content: req.file.buffer
            
        ]
    ;

    mailer.sendMail(mailOptions, function(err, res) 
        if (err)  
            console.log(err) 
        
        console.log(res);
    );
);

上面的例子将附件保存在内存中,如果经常上传大文件,这可能会很糟糕。您可以改为将文件写入磁盘:

var upload = multer( dest: '/uploads' );

然后,不是将文件的buffer 设置为附件的content,而是将附件的path 设置为文件的path

attachments: [
    
        filename: req.file.originalname,
        path: req.file.path
    
]

【讨论】:

代码中的一个小改动:formData.set(key, $scope.email[key]);应该是:formData.append(key, $scope.email[key]);跨度> 查看文档,我发现浏览器支持不如FormData.set()。我将更新我的答案以使用.append() @gilly3 您可以使用 ng-resource 并保存来自控制器的数据,然后使用已保存的 promise,然后触发文件上传。我说的对吗?

以上是关于使用 Sendgrid/Nodemailer 将 Angular 表单数据发布到 Node.js的主要内容,如果未能解决你的问题,请参考以下文章

R语言使用dplyr将特定的数据列移动到最前面使用dplyr将特定数据列移动到另一指定数据列的后面使用dplyr将特定数据列移动到另一指定数据列的前面

您将如何将 node.js 子进程与 discord.js 一起使用?

使用 ATL 编译 dll,将方法参数作为接口,但将它们作为 coclasses

使用 Tumbleweed 安全文件传输将文件发送到 S3

使用 VBA 将表单另存为报表

使用 jQuery 1.5 将请求作为 jsonp 发送,将响应解释为文本