【问题标题】:Sending multiple attachements dynamically using nodemailer使用 nodemailer 动态发送多个附件
【发布时间】:2019-09-30 22:05:05
【问题描述】:

我正在尝试使用 nodemailer 在 nodejs 中发送电子邮件。目前我将把手配置为模板,并使用 nodemailer-express-handlebars 作为模板引擎。我想动态读取上传文件夹中可用的文件并将它们作为附件发送。但我不知道怎么做。请帮帮我

import { FeedbackFileEntity } from 
 '../../shared/entities/feedback.file.entity';
import hbs = require('nodemailer-express-handlebars');

import fs = require('fs');
import { getConnection } from 'typeorm';
import { DaoException } from '../../shared/exceptionHandler/dao.exception';
import { AppEnvServiceInstance } from 
     '../../shared/services/app.env.service';
import nodemailer = require('nodemailer');
import * as path from 'path';
import { promisify } from 'util';

// This is the router to upload files to database
// this works fine
export const feedbackFileUploadDataLayer = async(fileMeta, fileBody) => {
    console.log('file buffer is', fileMeta);
    console.log('file meta path', fileMeta.path);


    fileEntity.$fileName = fileBody.fileName;
    const manager =  await getConnection('postgresConnection').manager;
    console.log('before triggering save');
    return new Promise((resolve, reject) => {
        manager.save(fileEntity).then(data => {
            console.log('Saved the data successfully', data);
            resolve('Saved the fileContent');
        }).catch(err => {
            console.log('error saving thge data', err);
            reject(new DaoException(481, 'Error in saving the file', 
           'DaoException'));
        });
    });

};

// this is the place where I will be implementing logic to generate new 
  files
// currently I am trying to read the files that was uploaded above from 
 ./uploads folder
export const generateFilesAndEmailDataLayer = async () => {

    console.log('inside data layer');
    // console.log("Preview URL: %s", 
    nodemailer.getTestMessageUrl(transportObject));
    const result = sendEmail();
    console.log('returned result', result);
    return result;
};

const sendEmail = () => {

    // create mail account -  in ethereal
    const accnt = {
        user: 'XXXX',
        pass: 'XXXXX'
    }

    // configure smptp
    const transport = nodemailer.createTransport({
        host: 'smtp.ethereal.email',
        port: 587,
        secure: false,
        auth: {
           user: accnt.user,
           pass: accnt.pass
        }
    });
    const emailTemplateOptions = {
        defaultLayout: 'email.default',
        layoutDir: 
  path.resolve(__dirname+'./../../../../views/email/layouts/'),
        partialsDir: 
   path.resolve(__dirname+'./../../../../views/email/partials/'),
        extName: 'hbs'
    }
    let options = {
        viewEngine: {

            extname: '.handlebars',
            layoutsDir: 
    path.resolve(__dirname+'./../../../../views/email/'),
            defaultLayout : 'template',
            partialsDir : 
    path.resolve(__dirname+'./../../../../views/email/partials/')
        },
        viewPath: path.resolve(__dirname+'./../../../../views/email/'),
        extName: '.handlebars'

    };




    transport.use('compile', hbs(options));
    var mail = {
        from: 'XXXX',
        to: 

   AppEnvServiceInstance.getConfigurationSettings().$SMTP_MAIL_RECEIPIENTS,
        subject: 'Feedback Generated Files',
        template: 'email.body',
        attachments: fileArrayFunction,
        context: {
            variable1 : 'value1',
            variable2 : 'value2',
            array1: ['JOhn', 'som', 'tet']
       }
     }
    console.log('evfore sending email', fileArrayFunction);

        transport.sendMail(mail, (err, info) => {
            if(!err) {
                console.log('info', info);
                return(info);
            }else {
                console.log('err', err);
                return(err);
            }
        });



    // e
}

const fileArrayFunction =  () => {
    const dirPath = path.join(__dirname+'./../../../../assests/uploads/');
    const filesArray = [];
    const rAsync = promisify(fs.readFile);
    const rAsyncDir = promisify(fs.readdir);
    // return new Promise((resolve, reject) => {
    //     rAsyncDir(dirPath).then(data => {
    //         console.log('durectory parth read', data);
    //         data.array.forEach(element => {
    //             console.log('each element is', element);
    //             rAsync(element).then(content => {
    //                 filesArray.push({fileName: element, 
    content:content});
    //             })
    //         });
    //         resolve(filesArray);
    //     }).catch(err => {
    //         console.log(err);
    //         reject(err);
    //     });
    // });
    fs.readdirSync(dirPath).forEach(item => {
        console.log('each item dur', item);
        const content = fs.readFileSync(dirPath+item);
        filesArray.push({filename: item, content:content});
    })

    return filesArray;
}

partials 目录,默认布局都可以正常工作。它们非常基础。这是主要的电子邮件模板 email.body.handlebars

<h4>Main Body Here</h4>
{{variable1}} <br/>
{{variable2}}

我可以发送不带附件的电子邮件,但如果添加此文件,您会看到编译时错误,说明 transport.sendEmail() 无法使用 ma​​il 常量,因为它包含附件作为函数而不是常量数组。请帮助我。我想在文件增长时读取文件并动态发送出去

【问题讨论】:

    标签: node.js typescript nodemailer express-handlebars


    【解决方案1】:

    我找到了答案。

    所以我写了一个这样的util服务

    retrieveMailConstants(data) {
            this.mailConstants = {
                from: 'a634885.fmr.com',
                to: AppEnvServiceInstance.getConfigurationSettings().$SMTP_MAIL_RECEIPIENTS,
                subject: 'Test files - Feedback Generated Files',
                template: 'email.body',
                attachments: data,
                context: {
                    variable1 : 'value1',
                    variable2 : 'value2',
                    array1: ['JOhn', 'som', 'tet']
               }
             }
    
             return this.mailConstants;
        }
    

    现在附件属性的数据应该是已解决的数据,可以是 Promise 已解决的数据,也可以是可观察的已解决数据数组。我选择使用 observables。 现在我的用例是我需要根据来自 DB 的配置信息生成许多文件,并将这些生成的文件存储在 DB 或单独的服务器中。现在我选择将它们保存在本地磁盘中。然后我从该位置读取所有文件,将其保存在一个数组中,最后将该数组推送到行为主体

    (注意我是用ts写的,你可以很方便的转换成js文件或者转译)

    import * as path from 'path';
    import { Attachment } from 'nodemailer/lib/mailer';
    import * as fs from 'fs';
    import * as _ from 'lodash';
    import { NodemailerAttachmentModel } from '../models/nodemailer.attachment.model';
    import { BehaviorSubject, Observable, of, ConnectableObservable } from 'rxjs';
    import {tap, map, filter, switchMap, share, publish, refCount, last, shareReplay} 
     from 'rxjs/operators';
    
    let fileAttachmentSubject = new BehaviorSubject<Attachment[]>([]);
    
    export const readFilesAndCreateAttachments = () => {
        console.log('ibside create attachments');
        console.log('dirname', __dirname);
        const dirPath = path.join(__dirname+'./../../../../assests/uploads/');
        console.log('dirparh is', dirPath);
        const filesArray =  new Array<Attachment>();
        const fileList = fs.readdirSync(dirPath);
        console.log('filelist is', fileList);
        _.each(fileList, (filePath, i) => {
            console.log('filepath in each is', filePath, 'index is', i, 'filelist each index', fileList[i]);
            if(i+1 >= fileList.length){
                // then it reached the end, time to call the observable list
                console.log('before sending', filesArray);
                setBehaviorSubject(filesArray);
            } else {
                console.log('path to read file is', dirPath+fileList[i]);
                fs.readFile(dirPath+fileList[i], (err, data) => {
                    if(!err){
                        const fileInDir = new NodemailerAttachmentModel;
                        fileInDir.$content = data;
                        fileInDir.$filename = filePath;
                        filesArray.push(fileInDir);
                        console.log('inside else', filesArray.length, i, 
                   fileList.length);
                    }
                });
    
            }
        });
    };
    
    export const setBehaviorSubject = (filesArray: Attachment[]) => {
     //fileAttachmentObs = from(filesArray).;
     fileAttachmentSubject.next(filesArray);
     console.log('subject is set', filesArray.length);
    }
    
    export const getBehaviorSubject = () => {
        console.log('call to get subject');
        return fileAttachmentSubject.asObservable();
    }
    

    现在我使用传输配置的邮件选项来发送电子邮件。此处未显示传输配置。这是一个基本的配置信息,可以从 nodemailer 站点获得

    getBehaviorSubject().subscribe(data => {
                console.log('data subscribed from subject', data);
                console.log('only then going to mail');
                let mailOptions  = nodemailerConstantInstance.retrieveMailConstants(data);
    
                console.log('before sending email');
                transport.sendMail(mailOptions, (err, info) => {
                if(!err) {
                    console.log('info', info);
                    resolve(info);
                }else {
                    console.log('err', err);
                    reject(err);
                }
            });
    

    希望它对某人有益。

    【讨论】:

      猜你喜欢
      • 2022-07-15
      • 1970-01-01
      • 2020-08-05
      • 2016-03-30
      • 2017-12-06
      • 1970-01-01
      • 2017-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多