BANNED_DOMAINS = {'qq.com':true}
fs = require('fs')
async = require('async')
winston = require('winston')
winston.remove(winston.transports.Console)
winston.add(winston.transports.Console, {level: 'debug', timestamp:true, colorize:true})
sendgrid = require("sendgrid")
misc = require('smc-util/misc')
{defaults, required} = misc
{SENDGRID_TEMPLATE_ID, SENDGRID_ASM_NEWSLETTER, COMPANY_NAME, COMPANY_EMAIL} = require('smc-util/theme')
email_server = undefined
exports.is_banned = is_banned = (address) ->
i = address.indexOf('@')
if i == -1
return false
x = address.slice(i+1).toLowerCase()
return !! BANNED_DOMAINS[x]
exports.send_email = send_email = (opts={}) ->
opts = defaults opts,
subject : required
body : required
fromname : COMPANY_NAME
from : COMPANY_EMAIL
to : required
replyto : undefined
replyto_name : undefined
cc : ''
bcc : ''
verbose : true
cb : undefined
category : undefined
asm_group : undefined
if opts.verbose
dbg = (m) -> winston.debug("send_email(to:#{opts.to}) -- #{m}")
else
dbg = (m) ->
dbg(opts.body)
if is_banned(opts.to) or is_banned(opts.from)
dbg("WARNING: attempt to send banned email")
opts.cb?('banned domain')
return
disabled = false
async.series([
(cb) ->
if email_server?
cb(); return
dbg("starting sendgrid client...")
filename = "#{process.env.SALVUS_ROOT}/data/secrets/sendgrid"
fs.readFile filename, 'utf8', (error, api_key) ->
if error
err = "unable to read the file '#{filename}', which is needed to send emails."
dbg(err)
cb(err)
else
api_key = api_key.toString().trim()
if api_key.length == 0
dbg("email_server: explicitly disabled -- so pretend to always succeed for testing purposes")
disabled = true
email_server = {disabled:true}
cb()
return
email_server = sendgrid(api_key)
dbg("started sendgrid client")
cb()
(cb) ->
if disabled or email_server?.disabled
cb(undefined, 'sendgrid email disabled -- no actual message sent')
return
dbg("sending email to #{opts.to} starting...")
helper = sendgrid.mail
from_email = new helper.Email(opts.from, opts.fromname)
to_email = new helper.Email(opts.to)
content = new helper.Content("text/html", opts.body)
mail = new helper.Mail(from_email, opts.subject, to_email, content)
if opts.replyto
replyto_name = opts.replyto_name ? opts.replyto
mail.setReplyTo(new helper.Email(opts.replyto, replyto_name))
personalization = new helper.Personalization()
personalization.setSubject(opts.subject)
personalization.addTo(to_email)
if opts.cc
personalization.addCc(new helper.Email(opts.cc))
if opts.bcc
personalization.addBcc(new helper.Email(opts.bcc))
if opts.category?
mail.addCategory(new helper.Category(opts.category))
if opts.asm_group?
mail.setAsm(new helper.Asm(opts.asm_group))
mail.setTemplateId(SENDGRID_TEMPLATE_ID)
personalization.addSubstitution(new helper.Substitution("#title#", opts.subject))
mail.addPersonalization(personalization)
request = email_server.emptyRequest
method : 'POST'
path : '/v3/mail/send'
body : mail.toJSON()
email_server.API request, (err, res) ->
dbg("sending email to #{opts.to} done...; got err=#{misc.to_json(err)} and res=#{misc.to_json(res)}")
if err
dbg("sending email -- error = #{misc.to_json(err)}")
else
dbg("sending email -- success = #{misc.to_json(res)}")
cb(err)
], (err, message) ->
if err
email_server = undefined
err = "error sending email -- #{misc.to_json(err)}"
dbg(err)
else
dbg("successfully sent email")
opts.cb?(err, message)
)
exports.mass_email = (opts) ->
opts = defaults opts,
subject : required
body : required
from : COMPANY_EMAIL
fromname : COMPANY_NAME
to : required
cc : ''
limit : 10
cb : undefined
dbg = (m) -> winston.debug("mass_email: #{m}")
dbg(opts.filename)
dbg(opts.subject)
dbg(opts.body)
success = []
recipients = undefined
async.series([
(cb) ->
if typeof(opts.to) != 'string'
recipients = opts.to
cb()
else
fs.readFile opts.to, (err, data) ->
if err
cb(err)
else
recipients = misc.split(data.toString())
cb()
(cb) ->
n = 0
f = (to, cb) ->
if n % 100 == 0
dbg("#{n}/#{recipients.length-1}")
n += 1
send_email
subject : opts.subject
body : opts.body
from : opts.from
fromname : opts.fromname
to : to
cc : opts.cc
asm_group: SENDGRID_ASM_NEWSLETTER
category : "newsletter"
verbose : false
cb : (err) ->
if not err
success.push(to)
cb()
else
cb("error sending email to #{to} -- #{err}")
async.mapLimit(recipients, opts.limit, f, cb)
], (err) ->
opts.cb?(err, success)
)