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

我已经遵循这个例子 ,从我的Angular应用程序发布数据到Node.js发布一个networking表单到Sendgrid。 这一切工作正常后,一些变化,并感谢很多快速入门。 将我的表单数据发送到Sendgrid正在工作!

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

但是,这个例子只有input字段和一个textarea。 我希望能够添加一个文件(PDF,Docx,例如),以便人们可以通过Sendgrid发送附件给收件人。 我已经寻找一个解决scheme,但找不到一个工作的例子。 也许因为这是不可能的,我想实现。

我的观点(客户):

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

那么有两个主要问题:

  1. 客户端:我怎样才能在这个表单中发布附件从Angular到Node? 我必须首先上传文件,还是可以通过$ http.post发送给Node? 或者我必须使用ng-file-upload?
  2. Serverside:我如何发送附件到Sendgrid / Nodemailer。 从服务器上的我的app.js发送一个硬编码的文件到Sendgrid不起作用。 邮件成功发送到Sendgrid,但不包含附件。

提前谢谢了!

1.以angular度上传文件

你遇到的第一个麻烦是ng-model不能和<input type="file" /> 。 所以,您将需要创build一个自定义指令来使用该文件填充模型。

 .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元素上使用这个指令:

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

注意我也传递了一个configuration对象到$http.post() 。 这是为了防止parsingFormData对象和设置内容types的angular度。

我非常依赖这个博客post来回答这个问题。

2.使用Nodemailer发送附件

要快速访问文件,请使用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自述部分,它表示使用属于attachment对象数组的attachment属性。

 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 } ] 

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

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

到以下代码:

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