0

可能重复:
psql 触发器发送电子邮件

我使用 PL/Perl 语言在 Postgresql 中发送邮件。当数据集表upload_status更改为已发布时,它会向数据集表中作者的电子邮件地址发送邮件。并且在信中包含该作者在数据集中的一些记录。数据集 PK 是标识符。

比如从 xx@mail.com 发送到 (dataset.email)@mail.com

亲爱的博士(dataset.author)

你的......(dataset.product)已经......

那么如何使用 PL/Perl 和触发函数编写函数。

谢谢,我使用这种方法http://evilrouters.net/2008/02/01/send-email-from-postgresql/

mydb=# CREATE OR REPLACE FUNCTION mydb_mytable_insert_send_mail_function()
mydb-# RETURNS "trigger" AS
mydb-# $BODY$
mydb$# use Mail::Sendmail;
mydb$#
mydb$# $message = "A new entry has been added to the 'mytable' table.\n\n";
mydb$# $message .= "The new name is: $_TD->{new}{name}\n\n";
mydb$#
mydb$# %mail = ( From => $_[0], To => $_[1], Subject => $_[2], Message => $message);
mydb$#
mydb$# sendmail(%mail) or die $Mail::Sendmail::error;
mydb$# return undef;
mydb$# $BODY$
mydb-# LANGUAGE 'plperlu' VOLATILE;

mydb=# CREATE TRIGGER mydb_mytable_insert_send_mail_trigger
mydb=# AFTER INSERT ON mytable
mydb=# FOR EACH ROW
mydb=# EXECUTE PROCEDURE mydb_mytable_insert_send_mail_function('from@domain.com',          'to@domain.com', 'subject here');

但它显示发生错误 Can't locate Mail/Sendmail.pm in @INC(@INC contains: /usr/...

4

2 回答 2

10

仅仅因为你可以并不意味着你应该。有更好的方法来做到这一点。不要直接从 PL 中执行此操作。如果您想忽略我的警告,请使用 PL/PerlU 并像使用任何其他电子邮件客户端一样编写它。您可以使用任何您喜欢的 CPAN 模块,让您的生活更轻松。

不去的两个理由:

1)如果您的交易中止/回滚怎么办?您已发送电子邮件但未对数据库进行相应更改。你在事务中做非事务性的事情。

2)如果您的电子邮件挂起等待响应,直到您在 2 分钟后获得 tcp 超时,该怎么办?你会忘记给客户发电子邮件吗?中止交易(不能发送电子邮件,不能说我们已经发货了!)?

这是个主意。不要这样做。感谢 PostgreSQL 出现此错误并将其移至另一个守护程序。

更好的方法是使用 LISTEN 和 NOTIFY 以及队列表。然后,您可以像这样创建一个表:

CREATE TABLE email_queue (
    id serial not null unique,
    email_from text,
    email_to text not null,
    body text not null
); 

CREATE FUNCTION email_queue_trigger() RETURNS TRIGGER 
LANGUAGE PLPGSQL AS $F$
    BEGIN
        NOTIFY emails_waiting;
    END;
$F$;

然后让您的存储过程插入到该表中。

然后,让第二个客户端应用程序在 emails_waiting 上侦听(sql 语句LISTEN emails_waiting),然后执行以下操作:

  1. 检查 email_queue 中是否有记录。如果没有,请转到 3。
  2. 读取数据、发送电子邮件、删除记录并提交。
  3. 当队列为空时,睡眠 x 秒
  4. 唤醒时,检查异步。通知(取决于客户端库,检查文档)。如果有,转1,如果没有,转3。

这允许您的电子邮件排队等待在您的交易中发送,并自动传递到另一个应用程序,然后如果您选择,该应用程序可以与 MTA 连接。

第二个客户端应用程序可以使用您知道的任何工具以您选择的语言编写。它的优点是可以在事务之外完成所有网络事务,因此如果您通过第二个 SMTP 服务器发送,并且连接挂起,您的整个数据库事务不会等待 2 分钟以使其超时并中止事务. 因此,对于未来的需求变化,它也更安全。

于 2012-09-03T08:41:00.947 回答
6

简短的回答:不要。

长答案:使用单独的流程发送电子邮件,并在数据库中记录发送的要求。

发送电子邮件可能会暂时失败,也可能会永久失败。迟早你会想要暂停发送电子邮件而不停止数据库的其余部分。然后有人会希望更改消息模板,而您并不想仅仅为此更新数据库。

您的解决方案可以像 message_queue 表和每分钟运行一次的 cron-job 或使用 LISTEN/NOTIFY 的守护程序一样简单。我已经这样做了几次,并且拥有一个单独的电子邮件发件人一直是更好的选择。

于 2012-09-03T08:34:43.857 回答