import { readFile , readdir } from "fs" ; import { getType } from "mime" ; import { Entity , factory } from "mimemessage" ; import { render } from "mustache" ; import * as path from "path" ; import { encode as quote } from "quoted-printable" ; import { promisify } from "util" ; /**
 * Message body type
 */ export interface MessageBody { text : string ; html : string ; } /**
 * Message attachment type
 */ export interface MessageAttachment { id : string ; type : string ; data : string ; } template TData export abstract class Message < TData > { /**
     * Base directory
     */ protected base : string ; param template param data public constructor ( protected template , protected data ) { this . base = path . join ( __dirname , ".." , template ) ; } return public abstract get subject ( ) : string ; return public async body ( ) { const [ text , html ] = await Promise . all ( [ promisify ( readFile ) ( path . resolve ( this . base , "index.txt" ) , "utf8" ) , promisify ( readFile ) ( path . resolve ( this . base , "index.html" ) , "utf8" ) ] ) ; return { text : render ( text , this . data ) , html : render ( html , this . data ) . replace ( /attachments\// , "cid:" ) } ; } return public async attachments ( ) { const base = path . resolve ( this . base , "attachments" ) ; const filelist = await promisify ( readdir ) ( base ) ; return Promise . all ( filelist . filter ( file => getType ( file ) === "image/png" ) . map ( async ( file ) => { const data = await promisify ( readFile ) ( path . resolve ( base , file ) ) ; return { id : file , type : getType ( file ) ! , data : data . toString ( "base64" ) . match ( /.{1,76}/g ) ! . join ( "\r\n" ) } ; } ) ) ; } return public async compose ( ) { const [ body , attachments ] = await Promise . all ( [ this . body ( ) , this . attachments ( ) ] ) ; const message = factory ( { contentType : "multipart/mixed" , body : [ factory ( { contentType : "multipart/alternative" , body : [ factory ( { contentType : "text/plain; charset=UTF-8" , contentTransferEncoding : "quoted-printable" , body : quote ( body . text ) } ) , factory ( { contentType : "text/html; charset=UTF-8" , contentTransferEncoding : "quoted-printable" , body : quote ( body . html ) } ) ] } ) , ... attachments . map ( attachment => { const entity = factory ( { contentType : attachment . type , contentTransferEncoding : "base64" , body : attachment . data } ) ; entity . header ( "Content-Disposition" , "inline" ) ; entity . header ( "Content-ID" , `<${ attachment . id }>` ) ; return entity ; } ) ] } ) ; message . header ( "Subject" , this . subject ) ; return message ; } }