Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>In my opinion, sending email in a trigger is not optimal.</p> <p>Instead, you should just insert to a queue table, and have a process run frequently that checks the table and sends the email.</p> <p>What happens if you get an error in your email procedure? It will force a rollback of your job completion status. Only you know whether that is minor or possibly catastrophic. But I can tell you for sure that DB best practice is to NOT do extended I/O during a DML operation.</p> <pre><code>CREATE TRIGGER TR_Jobs_EnqueueEmail_IU ON dbo.Jobs FOR INSERT, UPDATE AS SET NOCOUNT ON; INSERT dbo.EmailQueue (UserID, JobCode) SELECT UserID, JobCode FROM Inserted I LEFT JOIN Deleted D ON I.JobCode = D.JobCode -- or proper PK columns WHERE IsNull(D.Status, 'R') &lt;&gt; 'D' AND I.Status = 'D'; </code></pre> <p>Tables needed:</p> <pre><code>CREATE TABLE dbo.EmailQueue ( QueuedDate datetime NOT NULL CONSTRAINT DF_EmailQueue_QeueueDate DEFAULT (GetDate()), UserID int NOT NULL, JobCode int NOT NULL, CONSTRAINT PK_EmailQueue PRIMARY KEY CLUSTERED (QueuedDate, UserID, JobCode) ); CREATE TABLE dbo.EmailSent ( SentDate datetime NOT NULL CONSTRAINT DF_EmailSent_SentDate DEFAULT (GetDate()), QueuedDate datetime NOT NULL, UserID int NOT NULL, JobCode int NOT NULL, CONSTRAINT PK_EmailSent PRIMARY KEY CLUSTERED (SentDate, QueuedDate, UserID, JobCode) ); </code></pre> <p>Then, run the following stored procedure once a minute from a SQL Job:</p> <pre><code>CREATE PROCEDURE dbo.EmailProcess AS DECLARE @Email TABLE ( QueuedDate datetime, UserID int, JobCode int ); DECLARE @EmailAddress nvarchar(255), @JobCode int; WHILE 1 = 1 BEGIN DELETE TOP 1 Q.* OUTPUT Inserted.QueuedDate, Inserted.UserID, Inserted.JobCode INTO @Email (QueuedDate, UserID, JobCode) FROM dbo.EmailQueue Q WITH (UPDLOCK, ROWLOCK, READPAST) ORDER BY QueuedDate; IF @@RowCount = 0 RETURN; SELECT @EmailAddress = U.EmailAddress, @JobCode = E.JobCode FROM @Email E INNER JOIN dbo.User U ON E.UserID = U.UserID; EXEC dbo.SendMyEmail @EmailAddress, @JobCode; DELETE E OUTPUT QueuedDate, UserID, JobCode INTO dbo.EmailSent (QueuedDate, UserID, JobCode) FROM @Email E; END; </code></pre> <p>The delete pattern and locks I used are very specifically chosen. If you change them or change the delete pattern <em>in any way</em> it is almost certain you will break it. Handling locks and concurrency is <em>hard</em>. Don't change it.</p> <p>Note: I typed all the above without checking anything on a SQL Server. It is likely there are typos. Please forgive any.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload