sql >> データベース >  >> RDS >> Oracle

Oracleのログテーブルから電子メール本文にデータをエクスポートする方法

    Oracleからのメールの場合、PL/SQLパッケージで次の一般的な手順を使用します。

    CREATE OR REPLACE TYPE VARCHAR_TABLE_TYPE AS TABLE OF VARCHAR2(1000);
    /
    
    CREATE OR REPLACE PACKAGE Mailing AS
    
    PRIORITY_HIGH           CONSTANT INTEGER := 1;
    PRIORITY_NORMAL         CONSTANT INTEGER := 3;
    PRIORITY_LOW            CONSTANT INTEGER := 5;
    
    PROCEDURE SendMail(
        Subject IN VARCHAR2, 
        Message IN OUT CLOB, 
        ToMail IN VARCHAR_TABLE_TYPE,   
        FromMail IN VARCHAR2, FromName IN VARCHAR2,
        PRIORITY IN INTEGER DEFAULT PRIORITY_NORMAL,
        FileName IN VARCHAR2 DEFAULT NULL, 
        MimeType IN VARCHAR2 DEFAULT NULL, --> determines the MIME-Type of binary attachment "BinAttachment"
        TxtAttachment IN CLOB DEFAULT NULL, 
        BinAttachment IN BLOB DEFAULT NULL);
    
    
    END Mailing;
    /
    
    CREATE OR REPLACE PACKAGE BODY Mailing AS
    
    PROCEDURE SendMail(
        Subject IN VARCHAR2, 
        Message IN OUT CLOB, 
        ToMail IN VARCHAR_TABLE_TYPE,   
        FromMail IN VARCHAR2, FromName IN VARCHAR2,
        PRIORITY IN T_MAIL_PRIORITY DEFAULT PRIORITY_NORMAL,
        FileName IN VARCHAR2 DEFAULT NULL, 
        MimeType IN VARCHAR2 DEFAULT NULL,
        TxtAttachment IN CLOB DEFAULT NULL, 
        BinAttachment IN BLOB DEFAULT NULL) IS
    
        SMTP_PORT               CONSTANT INTEGER := 25;
        SMTP_SERVER             CONSTANT VARCHAR2(50):= 'mailhost';
        MIME_BOUNDARY           CONSTANT VARCHAR2(50) := '====Multipart.Boundary.689464861147414354====';
    
        con UTL_SMTP.CONNECTION;
        ret UTL_SMTP.REPLY;
        Charset VARCHAR2(20);
        Footer VARCHAR2(1000);
        Recipients VARCHAR2(1000);
    
        LobLen INTEGER;
        amount INTEGER := 8000;
        BUFFER VARCHAR2(32000);
        BUFFER_B RAW(48);
        OFFSET INTEGER := 1;
        isHTML BOOLEAN := REGEXP_LIKE(DBMS_LOB.SUBSTR(Message, 1000, 1), '(< *html)|(< *body)', 'i');
    
    BEGIN
    
        SELECT UTL_I18N.MAP_CHARSET(VALUE)
        INTO Charset
        FROM NLS_DATABASE_PARAMETERS
        WHERE parameter = 'NLS_CHARACTERSET';
    
        -- Append common footer to mail 
        Footer := 'Message from '||SYS_CONTEXT('USERENV', 'DB_NAME')||' sent at '||TO_CHAR(SYSDATE,'yyyy-mm-dd hh24:mi:ss');
        IF isHTML THEN
            Message := REPLACE(message, '</body>', '<p>'||Footer||'</p></body>');
        END IF;
    
        -- setup mail header
        con := UTL_SMTP.OPEN_CONNECTION(SMTP_SERVER, SMTP_PORT);
        ret := UTL_SMTP.HELO(con, SYS_CONTEXT('USERENV', 'DB_DOMAIN'));
        ret := UTL_SMTP.MAIL(con, FromMail);
        FOR i IN ToMail.FIRST..ToMail.LAST LOOP
            Recipients := Recipients ||ToMail(i)||',';
            ret := UTL_SMTP.RCPT(con, ToMail(i));
        END LOOP;
        ret := UTL_SMTP.OPEN_DATA(con);
    
        IF CONVERT(FromName, 'US7ASCII') = FromName THEN
            UTL_SMTP.WRITE_DATA(con, 'From: "'||FromName||'" <'||FromMail||'>'||UTL_TCP.CRLF);
        ELSE
            UTL_SMTP.WRITE_DATA(con, 'From: =?UTF-8?B?'|| UTL_ENCODE.TEXT_ENCODE(FromName, 'AL32UTF8', UTL_ENCODE.BASE64) ||'?= <'||FromMail||'>'||UTL_TCP.CRLF);
        END IF; 
        UTL_SMTP.WRITE_DATA(con, 'To: '||REGEXP_REPLACE(Recipients, ',$')||UTL_TCP.CRLF);
        IF CONVERT(Subject, 'US7ASCII') = Subject THEN
            UTL_SMTP.WRITE_DATA(con, 'Subject: '||Subject||UTL_TCP.CRLF);
        ELSE
            UTL_SMTP.WRITE_DATA(con, 'Subject: =?UTF-8?B?'|| REPLACE(REPLACE(UTL_ENCODE.TEXT_ENCODE(Subject, 'AL32UTF8', UTL_ENCODE.BASE64), CHR(13), NULL), CHR(10), NULL) ||'?='||UTL_TCP.CRLF);
        END IF;
        UTL_SMTP.WRITE_DATA(con, 'Date: '||TO_CHAR(CURRENT_TIMESTAMP, 'Dy, DD Mon YYYY hh24:mi:ss TZHTZM', 'NLS_DATE_LANGUAGE = American')||UTL_TCP.CRLF);  
        UTL_SMTP.WRITE_DATA(con, 'X-Priority: '||PRIORITY||UTL_TCP.CRLF);
        UTL_SMTP.WRITE_DATA(con, 'MIME-Version: 1.0' || UTL_TCP.CRLF);
    
        IF FileName IS NOT NULL THEN
            UTL_SMTP.WRITE_DATA(con, 'Content-Type: multipart/mixed; boundary="'||MIME_BOUNDARY||'"' || UTL_TCP.CRLF);
            UTL_SMTP.WRITE_DATA(con, 'Content-Disposition: inline'|| UTL_TCP.CRLF);
            UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);
            UTL_SMTP.WRITE_DATA(con, '--'||MIME_BOUNDARY || UTL_TCP.CRLF);
        END IF;
    
        IF isHTML THEN
            UTL_SMTP.WRITE_DATA(con, 'Content-Type: text/html; charset='||Charset || UTL_TCP.CRLF);
        ELSE 
            UTL_SMTP.WRITE_DATA(con, 'Content-Type: text/plain; charset='||Charset || UTL_TCP.CRLF);
        END IF;
        UTL_SMTP.WRITE_DATA(con, 'Content-Disposition: inline'|| UTL_TCP.CRLF);
    
    
        -- Mail Body
        UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);
        LobLen := DBMS_LOB.GETLENGTH(Message);
        LOOP
            EXIT WHEN OFFSET > LobLen;
            DBMS_LOB.READ(Message, amount, OFFSET, BUFFER);
            UTL_SMTP.WRITE_RAW_DATA(con, UTL_RAW.CAST_TO_RAW(BUFFER));
            OFFSET := OFFSET + amount;
        END LOOP;   
        UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);
        IF NOT isHTML THEN
            UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF || UTL_TCP.CRLF);
            UTL_SMTP.WRITE_DATA(con, Footer);
            UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);
        END IF;
    
        IF FileName IS NOT NULL THEN
            -- Mail Attachment
            UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);
            UTL_SMTP.WRITE_DATA(con, '--'||MIME_BOUNDARY || UTL_TCP.CRLF);
    
            OFFSET := 1;
            IF TxtAttachment IS NOT NULL THEN
                UTL_SMTP.WRITE_DATA(con, 'Content-Type: text/plain; charset='||Charset|| UTL_TCP.CRLF);
                UTL_SMTP.WRITE_DATA(con, 'Content-Disposition: attachment; filename="'||Filename||'"'|| UTL_TCP.CRLF);
                UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);                         
                LobLen := DBMS_LOB.GETLENGTH(TxtAttachment);
                LOOP
                    EXIT WHEN OFFSET > LobLen;
                    DBMS_LOB.READ(TxtAttachment, amount, OFFSET, BUFFER);
                    UTL_SMTP.WRITE_RAW_DATA(con, UTL_RAW.CAST_TO_RAW(BUFFER));
                    OFFSET := OFFSET + amount;
                END LOOP;
            ELSIF BinAttachment IS NOT NULL THEN
                UTL_SMTP.WRITE_DATA(con, 'Content-Type: '||MimeType||'; name="'||Filename||'"'|| UTL_TCP.CRLF);
                UTL_SMTP.WRITE_DATA(con, 'Content-Disposition: attachment; filename="'||Filename||'"'|| UTL_TCP.CRLF);
                UTL_SMTP.write_data(con, 'Content-Transfer-Encoding: base64' || UTL_TCP.crlf);
                UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);            
                amount := 48; -- must be a whole multiple of 3
                LobLen := DBMS_LOB.GETLENGTH(BinAttachment);
                LOOP
                    EXIT WHEN OFFSET > LobLen;
                    DBMS_LOB.READ(BinAttachment, amount, OFFSET, BUFFER_B);
                    UTL_SMTP.WRITE_RAW_DATA(con, UTL_ENCODE.BASE64_ENCODE(BUFFER_B));
                    OFFSET := OFFSET + amount;
                END LOOP;       
            END IF;
            UTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF);
            UTL_SMTP.WRITE_DATA(con, '--'||MIME_BOUNDARY||'--' || UTL_TCP.CRLF);
        END IF;
    
        -- finish mail
        ret := UTL_SMTP.CLOSE_DATA(con);
        ret := UTL_SMTP.QUIT(con);
    
    EXCEPTION
        WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN
            UTL_SMTP.QUIT(con);
    END SendMail;
    
    END Mailing;
    /
    

    それはいくつかの追加機能を提供します:

    • オプションでファイルを添付できます(txtまたはバイナリですが、サポートされているファイルは1つだけです)
    • From およびSubject öäüのような非ASCII文字が含まれる場合があります(もちろん、メール本文も含まれる場合があります)
    • 複数の受信者
    • データベースから正しい文字セットを自動的に使用する
    • プレーンテキストまたはHTMLメール本文を自動的に検出します
    • メールを示す一般的なフッター

    空の行を見逃さないように注意してくださいUTL_SMTP.WRITE_DATA(con, UTL_TCP.CRLF); 、適切なメールに必要です。

    次に、たとえば次のような手順を使用できます。

    DECLARE
        Message CLOB;
    BEGIN
    
        FOR aMsg IN (SELECT Log_id, Procedure_name, Fail_type, Message FROM log_messages ORDER BY Log_id) LOOP
            Message := Message || aMsg.Log_id ||' - '|| aMsg.Procedure_name ||' - '|| aMsg.Fail_type ||' - '|| aMsg.Message || CHR(13);
        end loop;
    
        SendMail(
            Subject => 'You got some logs', 
            Message => Message, 
            ToMail => VARCHAR_TABLE_TYPE('[email protected]'),   
            FromMail => '[email protected]', 
            FromName => 'Oracle User: '||USER);
    END;
    

    または、次のようにログを添付ファイルとして配置できます:

    DECLARE
        Message CLOB;
        Attachment CLOB;
    BEGIN
        Message := 'Open attachment to see log file';
        FOR aMsg IN (SELECT Log_id, Procedure_name, Fail_type, Message FROM log_messages ORDER BY Log_id) LOOP
            Attachment := Attachment || aMsg.Log_id ||' - '|| aMsg.Procedure_name ||' - '|| aMsg.Fail_type ||' - '|| aMsg.Message || CHR(13);
        end loop;
    
        Mailing.SendMail(
            Subject => 'You got some logs', 
            Message => Message, 
            ToMail => VARCHAR_TABLE_TYPE('[email protected]'),   
            FromMail => '[email protected]', 
            FromName => 'Oracle User: '||USER,
            TxtAttachment => Attachment,
            FileName => 'logfile.txt');
    END;
    


    1. MINまたはMAXにnull値を含めるにはどうすればよいですか?

    2. Ansibleを使用したPostgreSQLのデプロイとメンテナンス

    3. AttachDbFilenameの問題は何ですか

    4. SQL Serverのリンクサーバーから列の権限を返す(T-SQLの例)