好吧,毕竟这并不难。首先是简单的步骤:
第一步:准备数据库表来存储待处理的电子邮件记录:
class PendingEmail {
Date sentAt = new Date()
String fileName
static constraints = {
sentAt nullable: false
fileName nullable: false, blank:false
}
}
第二步:创建定期任务以发送待处理的电子邮件。注意mailSender 注入 - 它是原始 Grails 邮件插件的一部分,因此发送(及其配置!)是通过邮件插件进行的:
import javax.mail.internet.MimeMessage
class BackgroundEmailSenderJob {
def concurrent = false
def mailSender
static triggers = {
simple startDelay:15000l, repeatInterval: 30000l, name: "Background Email Sender"
}
def execute(context){
log.debug("sending pending emails via ${mailSender}")
// 100 at a time only
PendingEmail.list(max:100,sort:"sentAt",order:"asc").each { pe ->
// FIXME: do in transaction
try {
log.info("email ${pe.id} is to be sent")
// try to send
MimeMessage mm = mailSender.createMimeMessage(new FileInputStream(pe.fileName))
mailSender.send(mm)
// delete message
log.info("email ${pe.id} has been sent, deleting the record")
pe.delete(flush:true)
// delete file too
new File(pe.fileName).delete();
} catch( Exception ex ) {
log.error(ex);
}
}
}
}
第三步:创建一个可以被任何 Grails 代码(包括插件)使用的 mailService 的替代品。注意 mmbf 注入:这是来自 Mail Plugin 的 mailMessageBuilderFactory。该服务使用工厂将传入的 Closure 调用序列化为有效的 MIME 消息,然后将其保存到文件系统:
import java.io.File;
import org.springframework.mail.MailMessage
import org.springframework.mail.javamail.MimeMailMessage
class MyMailService {
def mmbf
MailMessage sendMail(Closure callable) {
log.info("sending mail using ${mmbf}")
if (isDisabled()) {
log.warn("No mail is going to be sent; mailing disabled")
return
}
def messageBuilder = mmbf.createBuilder(mailConfig)
callable.delegate = messageBuilder
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.call()
def m = messageBuilder.finishMessage()
if( m instanceof MimeMailMessage ) {
def fil = File.createTempFile("mail", ".mime")
log.debug("writing content to ${fil.name}")
m.mimeMessage.writeTo(new FileOutputStream(fil))
def pe = new PendingEmail(fileName: fil.absolutePath)
assert pe.save(flush:true)
log.debug("message saved for sending later: id ${pe.id}")
} else {
throw new IllegalArgumentException("expected MIME")
}
}
def getMailConfig() {
org.codehaus.groovy.grails.commons.ConfigurationHolder.config.grails.mail
}
boolean isDisabled() {
mailConfig.disabled
}
}
第四步:将Mail Plugin的mailService替换为修改后的版本,用工厂注入。在grails-app/conf/spring/resources.groovy:
beans = {
mailService(MyMailService) {
mmbf = ref("mailMessageBuilderFactory")
}
}
完成!
从现在开始,任何使用/注入 mailService 的插件或 Grails 代码都将获得对 MyMailService 的引用。该服务将接受发送电子邮件的请求,但不是发送它,而是将其序列化到磁盘上,将记录保存到数据库中。周期性任务将每 30 秒加载一次此类记录,并尝试使用原始邮件插件服务发送它们。
我已经测试过了,它似乎工作正常。我需要在这里和那里进行清理,在发送周围添加事务范围,使参数可配置等等,但骨架已经是一个可行的代码。
希望对某人有所帮助。