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');

しかし、それはエラーが発生したことを示しています

4

2 に答える 2

10

できないからといって、そうすべきだとは限りません。これを行うためのより良い方法があります。PLから直接実行しないでください。私の警告を無視したい場合は、PL / PerlUを使用して、他の電子メールクライアントと同じように記述してください。あなたはあなたの人生を楽にするあなたが好きなCPANモジュールを使うことができます。

しない2つの理由:

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でリッスンする2番目のクライアントアプリ(sqlステートメントLISTEN emails_waiting)を作成し、次のようにします。

  1. email_queueにレコードがあるかどうかを確認します。そうでない場合は3に進みます。
  2. データを読み取り、電子メールを送信し、レコードを削除して、コミットします。
  3. キューが空の場合、x秒間スリープします
  4. ウェイクアップ時に、非同期をチェックします。通知(クライアントライブラリによって異なります。ドキュメントを確認してください)。ある場合は1に進み、ない場合は3に進みます。

これにより、トランザクションを送信するために電子メールをキューに入れ、これを別のアプリケーションに自動的に渡して、必要に応じてMTAに接続できるようになります。

その2番目のクライアントアプリは、知っているツールを使用して、選択した言語で作成できます。トランザクションからすべてのネットワーク処理を実行できるという利点があるため、2番目のSMTPサーバーを介して送信しているときに接続がハングした場合、データベーストランザクション全体がタイムアウトしてトランザクションを中止するまで2分間待機しません。 。したがって、要件の将来の変更に対しても安全です。

于 2012-09-03T08:41:00.947 に答える
6

簡単な答え: しないでください。

長い答え: 別のプロセスを使用して電子メールを送信し、データベースに送信する必要があることを記録するだけです。

メールの送信は一時的に失敗する場合もあれば、永続的に失敗する場合もあります。遅かれ早かれ、データベースの残りの部分を停止することなく、電子メールの送信を一時停止したくなるでしょう。その後、誰かがメッセージ テンプレートの変更を要求しますが、そのためだけにデータベースを更新する必要はありません。

解決策は、message_queue テーブルと 1 分に 1 回実行される cron ジョブ、または LISTEN/NOTIFY を使用するデーモンと同じくらい簡単です。私はこれを数回行いましたが、別の電子メール送信者を持つことは常により良いオプションでした.

于 2012-09-03T08:34:43.857 に答える