Advertisement
Guest User

Untitled

a guest
Feb 16th, 2011
473
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
SQL 17.29 KB | None | 0 0
  1. ALTER PROCEDURE [sp_send_dbmail]
  2.    @profile_name               sysname    = NULL,        
  3.    @recipients                 VARCHAR(MAX)  = NULL,
  4.    @copy_recipients            VARCHAR(MAX)  = NULL,
  5.    @blind_copy_recipients      VARCHAR(MAX)  = NULL,
  6.    @subject                    NVARCHAR(255) = NULL,
  7.    @body                       NVARCHAR(MAX) = NULL,
  8.    @body_format                VARCHAR(20)   = NULL,
  9.    @importance                 VARCHAR(6)    = 'NORMAL',
  10.    @sensitivity                VARCHAR(12)   = 'NORMAL',
  11.    @file_attachments           NVARCHAR(MAX) = NULL,  
  12.    @query                      NVARCHAR(MAX) = NULL,
  13.    @execute_query_database     sysname       = NULL,  
  14.    @attach_query_result_as_file BIT          = 0,
  15.    @query_attachment_filename  NVARCHAR(260) = NULL,  
  16.    @query_result_header        BIT           = 1,
  17.    @query_result_width         INT           = 256,            
  18.    @query_result_separator     CHAR(1)       = ' ',
  19.    @exclude_query_output       BIT           = 0,
  20.    @append_query_error         BIT           = 0,
  21.    @query_no_truncate          BIT           = 0,
  22.    @query_result_no_padding    BIT           = 0,
  23.    @mailitem_id               INT            = NULL OUTPUT,
  24.    @from_address               VARCHAR(MAX)  = NULL,
  25.    @reply_to                   VARCHAR(MAX)  = NULL
  26.   WITH EXECUTE AS 'dbo'
  27. AS
  28. BEGIN
  29.     SET NOCOUNT ON
  30.  
  31.     -- And make sure ARITHABORT is on. This is the default for yukon DB's
  32.     SET ARITHABORT ON
  33.  
  34.     --Declare variables used by the procedure internally
  35.     DECLARE @profile_id         INT,
  36.             @temp_table_uid     uniqueidentifier,
  37.             @sendmailxml        VARCHAR(MAX),
  38.             @CR_str             NVARCHAR(2),
  39.             @localmessage       NVARCHAR(255),
  40.             @QueryResultsExist  INT,
  41.             @AttachmentsExist   INT,
  42.             @RetErrorMsg        NVARCHAR(4000), --Impose a limit on the error message length to avoid memory abuse
  43.             @rc                 INT,
  44.             @procName           sysname,
  45.             @trancountSave      INT,
  46.             @tranStartedBool    INT,
  47.             @is_sysadmin        BIT,
  48.             @send_request_user  sysname,
  49.             @database_user_id   INT,
  50.             @sid                varbinary(85)
  51.  
  52.     -- Initialize
  53.     SELECT  @rc                 = 0,
  54.             @QueryResultsExist  = 0,
  55.             @AttachmentsExist   = 0,
  56.             @temp_table_uid     = NEWID(),
  57.             @procName           = OBJECT_NAME(@@PROCID),
  58.             @tranStartedBool    = 0,
  59.             @trancountSave      = @@TRANCOUNT,
  60.             @sid                = NULL
  61.  
  62.     EXECUTE AS CALLER
  63.        SELECT @is_sysadmin       = IS_SRVROLEMEMBER('sysadmin'),
  64.               @send_request_user = SUSER_SNAME(),
  65.               @database_user_id  = USER_ID()
  66.     REVERT
  67.  
  68.     --Check if SSB is enabled in this database
  69.     IF (ISNULL(DATABASEPROPERTYEX(DB_NAME(), N'IsBrokerEnabled'), 0) <> 1)
  70.     BEGIN
  71.        RAISERROR(14650, 16, 1)
  72.        RETURN 1
  73.     END
  74.  
  75.     --Report error if the mail queue has been stopped.
  76.     --sysmail_stop_sp/sysmail_start_sp changes the receive status of the SSB queue
  77.     IF NOT EXISTS (SELECT * FROM sys.service_queues WHERE name = N'ExternalMailQueue' AND is_receive_enabled = 1)
  78.     BEGIN
  79.        RAISERROR(14641, 16, 1)
  80.        RETURN 1
  81.     END
  82.  
  83.     -- Get the relevant profile_id
  84.     --
  85.     IF (@profile_name IS NULL)
  86.     BEGIN
  87.         -- Use the global or users default if profile name is not supplied
  88.         SELECT TOP (1) @profile_id = pp.profile_id
  89.         FROM msdb.dbo.sysmail_principalprofile AS pp
  90.         WHERE (pp.is_default = 1) AND
  91.             (dbo.get_principal_id(pp.principal_sid) = @database_user_id OR pp.principal_sid = 0x00)
  92.         ORDER BY dbo.get_principal_id(pp.principal_sid) DESC
  93.  
  94.         --Was a profile found
  95.         IF(@profile_id IS NULL)
  96.         BEGIN
  97.             -- Try a profile lookup based on Windows Group membership, if any
  98.             EXEC @rc = msdb.dbo.sp_validate_user @send_request_user, @sid OUTPUT
  99.             IF (@rc = 0)
  100.             BEGIN
  101.                 SELECT TOP (1) @profile_id = pp.profile_id
  102.                 FROM msdb.dbo.sysmail_principalprofile AS pp
  103.                 WHERE (pp.is_default = 1) AND
  104.                       (pp.principal_sid = @sid)
  105.                 ORDER BY dbo.get_principal_id(pp.principal_sid) DESC
  106.             END
  107.  
  108.             IF(@profile_id IS NULL)
  109.             BEGIN
  110.                 RAISERROR(14636, 16, 1)
  111.                 RETURN 1
  112.             END
  113.         END
  114.     END
  115.     ELSE
  116.     BEGIN
  117.         --Get primary account if profile name is supplied
  118.         EXEC @rc = msdb.dbo.sysmail_verify_profile_sp @profile_id = NULL,
  119.                          @profile_name = @profile_name,
  120.                          @allow_both_nulls = 0,
  121.                          @allow_id_name_mismatch = 0,
  122.                          @profileid = @profile_id OUTPUT
  123.         IF (@rc <> 0)
  124.             RETURN @rc
  125.  
  126.         --Make sure this user has access to the specified profile.
  127.         --sysadmins can send on any profiles
  128.         IF ( @is_sysadmin <> 1)
  129.         BEGIN
  130.             --Not a sysadmin so check users access to profile
  131.             IF NOT EXISTS(SELECT *
  132.                         FROM msdb.dbo.sysmail_principalprofile
  133.                         WHERE ((profile_id = @profile_id) AND
  134.                                 (dbo.get_principal_id(principal_sid) = @database_user_id OR principal_sid = 0x00)))
  135.             BEGIN
  136.                 EXEC msdb.dbo.sp_validate_user @send_request_user, @sid OUTPUT
  137.                 IF(@sid IS NULL)
  138.                 BEGIN
  139.                     RAISERROR(14607, -1, -1, 'profile')
  140.                     RETURN 1
  141.                 END
  142.             END
  143.         END
  144.     END
  145.  
  146.     --Attach results must be specified
  147.     IF @attach_query_result_as_file IS NULL
  148.     BEGIN
  149.        RAISERROR(14618, 16, 1, 'attach_query_result_as_file')
  150.        RETURN 2
  151.     END
  152.  
  153.     --No output must be specified
  154.     IF @exclude_query_output IS NULL
  155.     BEGIN
  156.        RAISERROR(14618, 16, 1, 'exclude_query_output')
  157.        RETURN 3
  158.     END
  159.  
  160.     --No header must be specified
  161.     IF @query_result_header IS NULL
  162.     BEGIN
  163.        RAISERROR(14618, 16, 1, 'query_result_header')
  164.        RETURN 4
  165.     END
  166.  
  167.     -- Check if query_result_separator is specifed
  168.     IF @query_result_separator IS NULL OR DATALENGTH(@query_result_separator) = 0
  169.     BEGIN
  170.        RAISERROR(14618, 16, 1, 'query_result_separator')
  171.        RETURN 5
  172.     END
  173.  
  174.     --Echo error must be specified
  175.     IF @append_query_error IS NULL
  176.     BEGIN
  177.        RAISERROR(14618, 16, 1, 'append_query_error')
  178.        RETURN 6
  179.     END
  180.  
  181.     --@body_format can be TEXT (default) or HTML
  182.     IF (@body_format IS NULL)
  183.     BEGIN
  184.        SET @body_format = 'TEXT'
  185.     END
  186.     ELSE
  187.     BEGIN
  188.        SET @body_format = UPPER(@body_format)
  189.  
  190.        IF @body_format NOT IN ('TEXT', 'HTML')
  191.        BEGIN
  192.           RAISERROR(14626, 16, 1, @body_format)
  193.           RETURN 13
  194.        END
  195.     END
  196.  
  197.     --Importance must be specified
  198.     IF @importance IS NULL
  199.     BEGIN
  200.        RAISERROR(14618, 16, 1, 'importance')
  201.        RETURN 15
  202.     END
  203.  
  204.     SET @importance = UPPER(@importance)
  205.  
  206.     --Importance must be one of the predefined values
  207.     IF @importance NOT IN ('LOW', 'NORMAL', 'HIGH')
  208.     BEGIN
  209.        RAISERROR(14622, 16, 1, @importance)
  210.        RETURN 16
  211.     END
  212.  
  213.     --Sensitivity must be specified
  214.     IF @sensitivity IS NULL
  215.     BEGIN
  216.        RAISERROR(14618, 16, 1, 'sensitivity')
  217.        RETURN 17
  218.     END
  219.  
  220.     SET @sensitivity = UPPER(@sensitivity)
  221.  
  222.     --Sensitivity must be one of predefined values
  223.     IF @sensitivity NOT IN ('NORMAL', 'PERSONAL', 'PRIVATE', 'CONFIDENTIAL')
  224.     BEGIN
  225.        RAISERROR(14623, 16, 1, @sensitivity)
  226.        RETURN 18
  227.     END
  228.  
  229.     --Message body cannot be null. Atleast one of message, subject, query,
  230.     --attachments must be specified.
  231.     IF( (@body IS NULL AND @query IS NULL AND @file_attachments IS NULL AND @subject IS NULL)
  232.        OR
  233.     ( (LEN(@body) IS NULL OR LEN(@body) <= 0)  
  234.        AND (LEN(@query) IS NULL  OR  LEN(@query) <= 0)
  235.        AND (LEN(@file_attachments) IS NULL OR LEN(@file_attachments) <= 0)
  236.        AND (LEN(@subject) IS NULL OR LEN(@subject) <= 0)
  237.     )
  238.     )
  239.     BEGIN
  240.        RAISERROR(14624, 16, 1, '@body, @query, @file_attachments, @subject')
  241.        RETURN 19
  242.     END  
  243.     ELSE
  244.        IF @subject IS NULL OR LEN(@subject) <= 0
  245.           SET @subject='SQL Server Message'
  246.  
  247.     --Recipients cannot be empty. Atleast one of the To, Cc, Bcc must be specified
  248.     IF ( (@recipients IS NULL AND @copy_recipients IS NULL AND
  249.        @blind_copy_recipients IS NULL
  250.         )    
  251.        OR
  252.         ( (LEN(@recipients) IS NULL OR LEN(@recipients) <= 0)
  253.        AND (LEN(@copy_recipients) IS NULL OR LEN(@copy_recipients) <= 0)
  254.        AND (LEN(@blind_copy_recipients) IS NULL OR LEN(@blind_copy_recipients) <= 0)
  255.         )
  256.     )
  257.     BEGIN
  258.        RAISERROR(14624, 16, 1, '@recipients, @copy_recipients, @blind_copy_recipients')
  259.        RETURN 20
  260.     END
  261.  
  262.     --If query is not specified, attach results and no header cannot be true.
  263.     IF ( (@query IS NULL OR LEN(@query) <= 0) AND @attach_query_result_as_file = 1)
  264.     BEGIN
  265.        RAISERROR(14625, 16, 1)
  266.        RETURN 21
  267.     END
  268.  
  269.     --
  270.     -- Execute Query if query is specified
  271.     IF ((@query IS NOT NULL) AND (LEN(@query) > 0))
  272.     BEGIN
  273.         EXECUTE AS CALLER
  274.         EXEC @rc = sp_RunMailQuery
  275.                     @query                     = @query,
  276.                @attach_results            = @attach_query_result_as_file,
  277.                     @query_attachment_filename = @query_attachment_filename,
  278.                @no_output                 = @exclude_query_output,
  279.                @query_result_header       = @query_result_header,
  280.                @separator                 = @query_result_separator,
  281.                @echo_error                = @append_query_error,
  282.                @dbuse                     = @execute_query_database,
  283.                @width                     = @query_result_width,
  284.                 @temp_table_uid            = @temp_table_uid,
  285.             @query_no_truncate         = @query_no_truncate,
  286.             @query_result_no_padding           = @query_result_no_padding
  287.       -- This error indicates that query results size was over the configured MaxFileSize.
  288.       -- Note, an error has already beed raised in this case
  289.       IF(@rc = 101)
  290.          GOTO ErrorHandler;
  291.          REVERT
  292.  
  293.          -- Always check the transfer tables for data. They may also contain error messages
  294.          -- Only one of the tables receives data in the call to sp_RunMailQuery
  295.          IF(@attach_query_result_as_file = 1)
  296.          BEGIN
  297.              IF EXISTS(SELECT * FROM sysmail_attachments_transfer WHERE uid = @temp_table_uid)
  298.             SET @AttachmentsExist = 1
  299.          END
  300.          ELSE
  301.          BEGIN
  302.              IF EXISTS(SELECT * FROM sysmail_query_transfer WHERE uid = @temp_table_uid AND uid IS NOT NULL)
  303.             SET @QueryResultsExist = 1
  304.          END
  305.  
  306.          -- Exit if there was an error and caller doesn't want the error appended to the mail
  307.          IF (@rc <> 0 AND @append_query_error = 0)
  308.          BEGIN
  309.             --Error msg with be in either the attachment table or the query table
  310.             --depending on the setting of @attach_query_result_as_file
  311.             IF(@attach_query_result_as_file = 1)
  312.             BEGIN
  313.                --Copy query results from the attachments table to mail body
  314.                SELECT @RetErrorMsg = CONVERT(NVARCHAR(4000), attachment)
  315.                FROM sysmail_attachments_transfer
  316.                WHERE uid = @temp_table_uid
  317.             END
  318.             ELSE
  319.             BEGIN
  320.                --Copy query results from the query table to mail body
  321.                SELECT @RetErrorMsg = text_data
  322.                FROM sysmail_query_transfer
  323.                WHERE uid = @temp_table_uid
  324.             END
  325.  
  326.             GOTO ErrorHandler;
  327.          END
  328.          SET @AttachmentsExist = @attach_query_result_as_file
  329.     END
  330.     ELSE
  331.     BEGIN
  332.         --If query is not specified, attach results cannot be true.
  333.         IF (@attach_query_result_as_file = 1)
  334.         BEGIN
  335.            RAISERROR(14625, 16, 1)
  336.            RETURN 21
  337.         END
  338.     END
  339.  
  340.     --Get the prohibited extensions for attachments from sysmailconfig.
  341.     IF ((@file_attachments IS NOT NULL) AND (LEN(@file_attachments) > 0))
  342.     BEGIN
  343.         EXECUTE AS CALLER
  344.         EXEC @rc = sp_GetAttachmentData
  345.                         @attachments = @file_attachments,
  346.                         @temp_table_uid = @temp_table_uid,
  347.                         @exclude_query_output = @exclude_query_output
  348.         REVERT
  349.         IF (@rc <> 0)
  350.             GOTO ErrorHandler;
  351.        
  352.         IF EXISTS(SELECT * FROM sysmail_attachments_transfer WHERE uid = @temp_table_uid)
  353.             SET @AttachmentsExist = 1
  354.     END
  355.  
  356.     -- Start a transaction if not already in one.
  357.     -- Note: For rest of proc use GOTO ErrorHandler for falures  
  358.     IF (@trancountSave = 0)
  359.        BEGIN TRAN @procName
  360.  
  361.     SET @tranStartedBool = 1
  362.  
  363.     -- Store complete mail message for history/status purposes  
  364.     INSERT sysmail_mailitems
  365.     (
  366.        profile_id,  
  367.        recipients,
  368.        copy_recipients,
  369.        blind_copy_recipients,
  370.        subject,
  371.        body,
  372.        body_format,
  373.        importance,
  374.        sensitivity,
  375.        file_attachments,  
  376.        attachment_encoding,
  377.        query,
  378.        execute_query_database,
  379.        attach_query_result_as_file,
  380.        query_result_header,
  381.        query_result_width,          
  382.        query_result_separator,
  383.        exclude_query_output,
  384.        append_query_error,
  385.        send_request_user,
  386.        from_address,
  387.        reply_to
  388.     )
  389.     VALUES
  390.     (
  391.        @profile_id,        
  392.        @recipients,
  393.        @copy_recipients,
  394.        @blind_copy_recipients,
  395.        @subject,
  396.        @body,
  397.        @body_format,
  398.        @importance,
  399.        @sensitivity,
  400.        @file_attachments,  
  401.        'MIME',
  402.        @query,
  403.        @execute_query_database,  
  404.        @attach_query_result_as_file,
  405.        @query_result_header,
  406.        @query_result_width,            
  407.        @query_result_separator,
  408.        @exclude_query_output,
  409.        @append_query_error,
  410.        @send_request_user,
  411.        @from_address,
  412.        @reply_to
  413.     )
  414.  
  415.     SELECT @rc          = @@ERROR,
  416.            @mailitem_id = SCOPE_IDENTITY()
  417.  
  418.     IF(@rc <> 0)
  419.         GOTO ErrorHandler;
  420.  
  421.     --Copy query into the message body
  422.     IF(@QueryResultsExist = 1)
  423.     BEGIN
  424.       -- if the body is null initialize it
  425.         UPDATE sysmail_mailitems
  426.         SET body = N''
  427.         WHERE mailitem_id = @mailitem_id
  428.         AND body IS NULL
  429.  
  430.         --Add CR, a \r followed by \n, which is 0xd and then 0xa
  431.         SET @CR_str = CHAR(13) + CHAR(10)
  432.         UPDATE sysmail_mailitems
  433.         SET body.WRITE(@CR_str, NULL, NULL)
  434.         WHERE mailitem_id = @mailitem_id
  435.  
  436.    --Copy query results to mail body
  437.         UPDATE sysmail_mailitems
  438.         SET body.WRITE( (SELECT text_data FROM sysmail_query_transfer WHERE uid = @temp_table_uid), NULL, NULL )
  439.         WHERE mailitem_id = @mailitem_id
  440.  
  441.     END
  442.  
  443.     --Copy into the attachments table
  444.     IF(@AttachmentsExist = 1)
  445.     BEGIN
  446.         --Copy temp attachments to sysmail_attachments      
  447.         INSERT INTO sysmail_attachments(mailitem_id, filename, filesize, attachment)
  448.         SELECT @mailitem_id, filename, filesize, attachment
  449.         FROM sysmail_attachments_transfer
  450.         WHERE uid = @temp_table_uid
  451.     END
  452.  
  453.     -- Create the primary SSB xml maessage
  454.     SET @sendmailxml = '<requests:SendMail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.microsoft.com/databasemail/requests RequestTypes.xsd" xmlns:requests="http://schemas.microsoft.com/databasemail/requests"><MailItemId>'
  455.                         + CONVERT(NVARCHAR(20), @mailitem_id) + N'</MailItemId></requests:SendMail>'
  456.  
  457.     -- Send the send request on queue.
  458.     EXEC @rc = sp_SendMailQueues @sendmailxml
  459.     IF @rc <> 0
  460.     BEGIN
  461.        RAISERROR(14627, 16, 1, @rc, 'send mail')
  462.        GOTO ErrorHandler;
  463.     END
  464.  
  465.     -- Print success message if required
  466.     IF (@exclude_query_output = 0)
  467.     BEGIN
  468.        SET @localmessage = FORMATMESSAGE(14635)
  469.        PRINT @localmessage
  470.     END  
  471.  
  472.     --
  473.     -- See if the transaction needs to be commited
  474.     --
  475.     IF (@trancountSave = 0 AND @tranStartedBool = 1)
  476.        COMMIT TRAN @procName
  477.  
  478.     -- All done OK
  479.     GOTO ExitProc;
  480.  
  481.     -----------------
  482.     -- Error Handler
  483.     -----------------
  484. ErrorHandler:
  485.     IF (@tranStartedBool = 1)
  486.        ROLLBACK TRAN @procName
  487.  
  488.     ------------------
  489.     -- Exit Procedure
  490.     ------------------
  491. ExitProc:
  492.    
  493.     --Always delete query and attactment transfer records.
  494.    --Note: Query results can also be returned in the sysmail_attachments_transfer table
  495.     DELETE sysmail_attachments_transfer WHERE uid = @temp_table_uid
  496.     DELETE sysmail_query_transfer WHERE uid = @temp_table_uid
  497.  
  498.    --Raise an error it the query execution fails
  499.    -- This will only be the case when @append_query_error is set to 0 (false)
  500.    IF( (@RetErrorMsg IS NOT NULL) AND (@exclude_query_output=0) )
  501.    BEGIN
  502.       RAISERROR(14661, -1, -1, @RetErrorMsg)
  503.    END
  504.  
  505.     RETURN (@rc)
  506. END
  507.  
  508. GO
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement