Created
December 25, 2011 13:01
-
-
Save seraphy/1519233 to your computer and use it in GitHub Desktop.
Oracle11gR2 Expressで本文UTF8エンコードの添付ファイルつきメール送信用ヘルパをパッケージとして作ってみた。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE OR REPLACE PACKAGE MAILHELPER AS | |
/** | |
* SMTP接続先サーバ | |
*/ | |
VC_MAILHOST VARCHAR2(64) := '127.0.0.1'; | |
/** | |
* SMTP接続先ポート | |
*/ | |
VC_MAILPORT NUMBER := 25; | |
/** | |
* メールアドレスの情報 | |
*/ | |
TYPE MAIL_ADDRESS IS RECORD( | |
/** | |
* アドレスの表記、不要ならばNULL | |
*/ | |
DESCRIPTION NVARCHAR2(64), | |
/** | |
* アドレス. | |
* (RFCでは、メールアドレスは全体で256文字) | |
*/ | |
EMAIL VARCHAR2(256) | |
); | |
/** | |
* メールアドレス情報のリスト | |
*/ | |
TYPE MAIL_ADDRESS_LIST IS TABLE OF MAIL_ADDRESS INDEX BY binary_integer; | |
/** | |
* 添付ファイル情報 | |
*/ | |
TYPE ATTACHED_FILE IS RECORD( | |
/** | |
* 添付ファイル名. | |
* UTF8/16進数でのエンコードで出力される. | |
*/ | |
FILE_NAME NVARCHAR2(256), | |
/** | |
* コンテンツタイプ。 | |
* text/csvとか、application/octet-streamなど。 | |
*/ | |
CONTENT_TYPE VARCHAR2(48), | |
/** | |
* 添付ファイルとするバイナリデータ | |
*/ | |
CONTENT BLOB | |
); | |
/** | |
* 複数添付ファイル | |
*/ | |
TYPE ATTACHED_FILES IS TABLE OF ATTACHED_FILE INDEX BY binary_integer; | |
/** | |
* 添付なしのメール送信を行う。 | |
* @param p_from 送信元メールアドレス | |
* @param p_to 送信先メールアドレス | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from NVARCHAR2, | |
p_to NVARCHAR2, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2 | |
); | |
/** | |
* 添付なしのメール送信を行う。 | |
* @param p_from 送信元メールアドレス情報 | |
* @param p_to 送信先メールアドレス情報のリスト | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from MAIL_ADDRESS, | |
p_to_list MAIL_ADDRESS_LIST, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2 | |
); | |
/** | |
* 添付ファイルありのメール送信を行う. | |
* @param p_from 送信元メールアドレス | |
* @param p_to 送信先メールアドレス | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
* @param p_file 添付ファイル情報 | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from NVARCHAR2, | |
p_to NVARCHAR2, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2, | |
p_file ATTACHED_FILE | |
); | |
/** | |
* 添付ファイルありのメール送信を行う. | |
* @param p_from 送信元メールアドレス情報 | |
* @param p_to_list 送信先メールアドレス情報のリスト | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
* @param p_files 添付ファイル情報 | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from MAIL_ADDRESS, | |
p_to_list MAIL_ADDRESS_LIST, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2, | |
p_files ATTACHED_FILES | |
); | |
END MAILHELPER; | |
/ | |
CREATE OR REPLACE package body MAILHELPER as | |
-- UTF8のOracle表現 | |
UTF8 constant nvarchar2(250) := 'AL32UTF8'; | |
-- 改行コード | |
CRLF CONSTANT VARCHAR2(2) := chr(13) || chr(10); | |
-- タブコード | |
TAB CONSTANT VARCHAR2(1) := chr(9); | |
-- 内部用、UTL_SMTPのハンドル | |
vHANDLE UTL_SMTP.CONNECTION; | |
/** | |
* 引数に指定した非ASCII文字を含む文字列を、UTF8/BASE64でエンコードし | |
* 80桁以内に収まるように折り返した複数行形式のデータに変換して返す. | |
* 返されたRAW型はASCII文字だけを含んでおり、メールヘッダの値として使用できる. | |
* 末尾に改行コードを付与するか指定することが可能. | |
*/ | |
FUNCTION MAKE_HEADER_VALUE( | |
p_value NVARCHAR2, | |
p_CRLF BOOLEAN := TRUE | |
) RETURN RAW IS | |
-- ヘッダ部のUTF-8/BASE64エンコード開始マーカー | |
ENCMARK constant varchar2(10) := '=?UTF-8?B?'; | |
-- ヘッダ部のエンコード終了マーカー | |
ENCMARK_EN constant varchar2(2) := '?='; | |
-- 変換結果 (32KiBが最大) | |
ret RAW(32767); | |
BEGIN | |
DECLARE | |
-- エンコード後のヘッダ行を1行80byteに納めるための分割文字数 | |
-- UTF8なので日本語は3バイト程度に膨らむことを想定 (サロゲートペアは考慮外) | |
-- BASE64なので1.333倍に膨らむことを想定 | |
CHUNKSIZE CONSTANT PLS_INTEGER := 12; | |
-- 入力データ(p_value)の文字数 | |
MXLEN CONSTANT PLS_INTEGER := LENGTH(p_value); | |
-- 現在処理中の桁 | |
pos PLS_INTEGER := 1; | |
-- 1行ごとに処理する対象文字列の切り出しバッファ | |
linechunk NVARCHAR2(12); | |
-- BASE64エンコード処理用バッファ | |
rawdata RAW(80); | |
BEGIN | |
LOOP | |
-- すべて処理したらループ終了 | |
EXIT WHEN pos > MXLEN; | |
-- 分割後であれば改行+タブ | |
IF pos > 1 THEN | |
ret := UTL_RAW.CONCAT( | |
ret, | |
UTL_I18N.STRING_TO_RAW(CRLF || TAB, UTF8) | |
); | |
END IF; | |
-- 分割文字列の取得 | |
linechunk := substr(p_value, pos, CHUNKSIZE); | |
-- UTF8に変換 | |
rawdata := UTL_I18N.STRING_TO_RAW(linechunk, UTF8); | |
IF rawdata IS NULL THEN | |
RAISE_APPLICATION_ERROR(-20101, 'UTF8に変換できません。', FALSE); | |
END IF; | |
-- 出力 | |
ret := UTL_RAW.CONCAT( | |
ret, | |
UTL_I18N.STRING_TO_RAW(ENCMARK, UTF8), | |
UTL_ENCODE.BASE64_ENCODE(rawdata), | |
UTL_I18N.STRING_TO_RAW(ENCMARK_EN, UTF8) | |
); | |
-- 次の位置へ進む | |
pos := pos + chunksize; | |
END LOOP; | |
IF p_CRLF THEN | |
-- 改行終端 | |
ret := UTL_RAW.CONCAT( | |
ret, | |
UTL_I18N.STRING_TO_RAW(CRLF, UTF8) | |
); | |
END IF; | |
END; | |
RETURN ret; | |
END; | |
/** | |
* 添付ファイルのファイル名のエンコードをRFC2231により行う. | |
* 「filename*N*=xxxx」の形式の複数行となり、継続する場合は末尾はセミコロンとなる。 | |
* エンコードは文字コード名の識別子につづいて16進数でエンコードされた文字が続く. | |
* (例) filename*0*=UTF-8''%E6%96%B0%E8%A6 | |
* http://www.asahi-net.or.jp/~BD9Y-KTU/htmlrel_f/dtd_f/rfc_f/rfc2231j.html | |
* http://adiary.blog.abk.nu/0253 | |
* @param filename 添付ファイル名 | |
* @return UTF8の16進数表現でエンコードされたファイル名表現 | |
*/ | |
FUNCTION MAKE_ATTACHED_FILE_NAME(filename NVARCHAR2) RETURN RAW AS | |
buf RAW(32760); | |
c RAW(1); | |
pos PLS_INTEGER := 1; | |
mxlen PLS_INTEGER; | |
linebuf VARCHAR2(80) := 'UTF-8'''''; | |
TYPE t_lines IS TABLE OF VARCHAR2(80) INDEX BY binary_integer; | |
lines t_lines; | |
BEGIN | |
IF filename IS NULL THEN | |
RETURN NULL; | |
END IF; | |
-- ファイル名をUTF8のバイナリに変換 | |
buf := UTL_I18N.STRING_TO_RAW(filename, UTF8); | |
-- バイナリから「16進数」の文字列に変換。 | |
-- 54文字を超えた場合は次の行に折り返す. | |
mxlen := UTL_RAW.LENGTH(buf); | |
LOOP | |
EXIT WHEN pos > mxlen; | |
IF LENGTH(linebuf) > 54 THEN | |
lines(lines.COUNT) := linebuf || ';'; | |
linebuf := NULL; | |
END IF; | |
c := utl_raw.substr(buf, pos, 1); | |
linebuf := linebuf || '%' || rawtohex(c); | |
pos := pos + 1; | |
END LOOP; | |
lines(lines.COUNT) := linebuf; | |
-- ヘッダを構築してバイナリとして構築する. | |
buf := NULL; | |
FOR idx IN lines.FIRST .. lines.LAST | |
LOOP | |
IF lines.COUNT > 1 THEN | |
linebuf := TAB || 'filename*' || idx || '*=' || lines(idx); | |
ELSE | |
linebuf := TAB || 'filename*=' || lines(0); | |
END IF; | |
buf := UTL_RAW.CONCAT( | |
buf, | |
UTL_RAW.CAST_TO_RAW(linebuf), | |
UTL_RAW.CAST_TO_RAW(CRLF) | |
); | |
END LOOP; | |
RETURN buf; | |
END; | |
/** | |
* 内部用. | |
* From/Toなどのメールアドレスをもつヘッダを出力する。 | |
* @param p_header ヘッダ | |
* @param p_to_list メールアドレスのリスト | |
*/ | |
PROCEDURE WRITE_ADDRESS( | |
p_header VARCHAR2, | |
p_address_list MAIL_ADDRESS_LIST | |
) AS | |
BEGIN | |
-- ヘッダキー | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW(p_header) | |
) | |
); | |
-- メールアドレスの個数分繰り返す | |
FOR idx IN p_address_list.FIRST .. p_address_list.LAST | |
LOOP | |
IF idx > 1 THEN | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_I18N.STRING_TO_RAW(', '), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW(TAB) | |
) | |
); | |
END IF; | |
-- メールの表記が指定されていればUTF8+BASE64のMIMEヘッダエンコードで | |
-- 出力する。(必要に応じて継続行にする。) | |
DECLARE | |
description NVARCHAR2(60) := p_address_list(idx).DESCRIPTION; | |
mailaddr VARCHAR2(256) := p_address_list(idx).EMAIL; | |
nameraw RAW(32767); | |
linelen PLS_INTEGER; | |
BEGIN | |
IF description IS NOT NULL THEN | |
-- エンコードしたアドレス表記を出力 | |
nameraw := MAKE_HEADER_VALUE(description, FALSE); | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
nameraw | |
); | |
-- アドレス部をつづけて出力できるか、継続行にするか判定 | |
linelen := UTL_RAW.LENGTH(nameraw) + length(mailaddr); | |
IF linelen >= 70 THEN -- アドレス前後の山括弧とヘッダ名を含まず | |
-- EMAILを出力するに桁数が足りない場合は継続行とする. | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW(TAB) | |
) | |
); | |
ELSE | |
-- つづけてアドレス出力可能 | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CAST_TO_RAW(' ') | |
); | |
END IF; | |
END IF; | |
END; | |
-- メールアドレスの出力。 | |
-- 前後には山括弧をつける。 | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_I18N.STRING_TO_RAW('<'), | |
UTL_I18N.STRING_TO_RAW(p_address_list(idx).EMAIL), | |
UTL_I18N.STRING_TO_RAW('>') | |
) | |
); | |
END LOOP; | |
-- ヘッダ終端 | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CAST_TO_RAW(CRLF) | |
); | |
END; | |
/** | |
* 内部用. | |
* UTL_SMTPメール送信でハンドルを取得、送信先と基本ヘッダの設定までを行う. | |
* @param p_from 送信元メールアドレス | |
* @para, p_to 送信先メールアドレス | |
* @param p_subject 件名 | |
*/ | |
PROCEDURE OPEN_MAIL( | |
p_from MAIL_ADDRESS, | |
p_to_list MAIL_ADDRESS_LIST, | |
p_subject NVARCHAR2 | |
) AS | |
p_from_list MAIL_ADDRESS_LIST; | |
BEGIN | |
p_from_list(1) := p_from; | |
-- SMTPサーバへの接続 | |
vHANDLE := UTL_SMTP.OPEN_CONNECTION(VC_MAILHOST, VC_MAILPORT); | |
BEGIN | |
UTL_SMTP.HELO(vHANDLE, VC_MAILHOST); | |
-- MAIL FROM | |
UTL_SMTP.MAIL(vHANDLE, '<' || p_from.EMAIL || '>'); | |
-- RCPT TOを宛先ごとに繰り返す | |
FOR idx IN p_to_list.FIRST .. p_to_list.LAST | |
LOOP | |
UTL_SMTP.RCPT(vHANDLE, '<' || p_to_list(idx).EMAIL || '>'); | |
END LOOP; | |
-- メールデータ開始 | |
UTL_SMTP.OPEN_DATA(vHANDLE); | |
-- FROMヘッダ | |
WRITE_ADDRESS('From: ', p_from_list); | |
-- TOヘッダ | |
WRITE_ADDRESS('To: ', p_to_list); | |
-- 件名ヘッダ | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CAST_TO_RAW('Subject: ') | |
); | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
MAKE_HEADER_VALUE(p_subject) | |
); | |
EXCEPTION WHEN OTHERS THEN | |
BEGIN | |
-- コネクションをクローズする. | |
UTL_SMTP.QUIT(vHANDLE); | |
EXCEPTION WHEN OTHERS THEN | |
-- クローズの失敗は無視する. | |
NULL; | |
END; | |
vHANDLE := NULL; | |
RAISE; | |
END; | |
END; | |
/** | |
* メールオープン後の状態において、メール送信を閉じる. | |
*/ | |
PROCEDURE QUIT_MAIL(p_abort IN BOOLEAN) IS | |
BEGIN | |
IF vHANDLE.HOST IS NOT NULL THEN | |
IF p_abort THEN | |
BEGIN | |
-- メールデータ破棄 | |
UTL_SMTP.RSET(vHANDLE); | |
EXCEPTION WHEN OTHERS THEN | |
-- 破棄の失敗は無視する. | |
NULL; | |
END; | |
ELSE | |
-- メールデータ完了 | |
UTL_SMTP.CLOSE_DATA(vHANDLE); | |
END IF; | |
BEGIN | |
-- コネクションをクローズする. | |
UTL_SMTP.QUIT(vHANDLE); | |
EXCEPTION WHEN OTHERS THEN | |
-- クローズの失敗は無視する. | |
NULL; | |
END; | |
-- ハンドルをクリアする. | |
vHANDLE := NULL; | |
END IF; | |
END; | |
/** | |
* 添付なしのメール送信を行う。 | |
* @param p_from 送信元メールアドレス | |
* @param p_to 送信先メールアドレス | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from NVARCHAR2, | |
p_to NVARCHAR2, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2 | |
) AS | |
p_to_list MAIL_ADDRESS_LIST; | |
v_mail_from MAIL_ADDRESS; | |
v_mail_to MAIL_ADDRESS; | |
BEGIN | |
v_mail_from.EMAIL := p_from; | |
v_mail_to.EMAIL := p_to; | |
p_to_list(1) := v_mail_to; | |
SENDMAIL(v_mail_from, p_to_list, p_subject, p_message); | |
END; | |
/** | |
* 添付なしのメール送信を行う。 | |
* @param p_from 送信元メールアドレス | |
* @param p_to 送信先メールアドレスのリスト | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from MAIL_ADDRESS, | |
p_to_list MAIL_ADDRESS_LIST, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2 | |
) IS | |
BEGIN | |
OPEN_MAIL(p_from, p_to_list, p_subject); | |
BEGIN | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW('MIME-version: 1.0'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW('Content-type: text/plain; '), | |
UTL_RAW.CAST_TO_RAW('charset=UTF-8'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW('Content-transfer-encoding: BASE64'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_ENCODE.BASE64_ENCODE( | |
UTL_I18N.STRING_TO_RAW(p_message, UTF8) | |
) | |
) | |
); | |
QUIT_MAIL(p_abort => false); | |
EXCEPTION WHEN OTHERS THEN | |
QUIT_MAIL(p_abort => true); | |
RAISE_APPLICATION_ERROR(-20120, 'メール送信に失敗しました。' || SQLERRM, TRUE); | |
END; | |
END; | |
/** | |
* 1個の添付ファイルありのメール送信を行う. | |
* @param p_from 送信元メールアドレス | |
* @param p_to 送信先メールアドレス | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
* @param p_file 添付ファイル情報 | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from NVARCHAR2, | |
p_to NVARCHAR2, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2, | |
p_file ATTACHED_FILE | |
) AS | |
p_files ATTACHED_FILES; | |
p_to_list MAIL_ADDRESS_LIST; | |
v_mail_from MAIL_ADDRESS; | |
v_mail_to MAIL_ADDRESS; | |
BEGIN | |
v_mail_from.EMAIL := p_from; | |
v_mail_to.EMAIL := p_to; | |
p_to_list(1) := v_mail_to; | |
p_files(p_files.COUNT + 1) := p_file; | |
SENDMAIL(v_mail_from, p_to_list, p_subject, p_message, p_files); | |
END; | |
/** | |
* 添付ファイルありのメール送信を行う. | |
* ただし、p_filesが空である場合は添付なしで送信される. | |
* @param p_from 送信元メールアドレス | |
* @param p_to_list 送信先メールアドレス | |
* @param p_subject 件名 | |
* @param p_message 本文 | |
* @param p_files 添付ファイル情報のコレクション、空の場合は添付なし | |
*/ | |
PROCEDURE SENDMAIL( | |
p_from MAIL_ADDRESS, | |
p_to_list MAIL_ADDRESS_LIST, | |
p_subject NVARCHAR2, | |
p_message NVARCHAR2, | |
p_files ATTACHED_FILES | |
) AS | |
SEPARATOR CONSTANT varchar2(50) := '----_' || DBMS_RANDOM.STRING('A', 45); | |
BEGIN | |
IF p_files.FIRST IS NULL THEN | |
-- 添付ファイルなしの場合 | |
SENDMAIL(p_from, p_to_list, p_subject, p_message); | |
RETURN; | |
END IF; | |
OPEN_MAIL(p_from, p_to_list, p_subject); | |
BEGIN | |
-- ヘッダ部の作成 (MIME) | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW('MIME-version: 1.0'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW('Content-type: multipart/mixed;'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW(' boundary=' || SEPARATOR), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW(CRLF) | |
) | |
); | |
-- 本文の作成 | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW('--' || SEPARATOR), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW('Content-Type: text/plain; '), | |
UTL_RAW.CAST_TO_RAW('Charset=UTF-8'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW('Content-transfer-encoding: BASE64'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
UTL_ENCODE.BASE64_ENCODE( | |
UTL_I18N.STRING_TO_RAW(p_message, UTF8) | |
), | |
UTL_RAW.CAST_TO_RAW(CRLF) | |
) | |
); | |
-- すべての添付ファイルを出力するループ | |
FOR idx IN p_files.FIRST .. p_files.LAST | |
LOOP | |
DECLARE | |
-- 対象添付ファイル | |
p_file ATTACHED_FILE := p_files(idx); | |
BEGIN | |
-- 添付ファイル開始 | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW('--' || SEPARATOR), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
-- 添付ファイルのコンテンツタイプ | |
UTL_RAW.CAST_TO_RAW('Content-Type: ' | |
|| p_file.CONTENT_TYPE || ';' || CRLF || TAB || 'name="'), | |
-- MIMEによるファイル名の指定 (Outlookなどは、こちらで認識する。) | |
MAKE_HEADER_VALUE(p_file.FILE_NAME, FALSE), | |
UTL_RAW.CAST_TO_RAW('"' || CRLF), | |
-- 添付ファイルのファイル名 | |
-- Thunderbirdなどは、こちらで認識する。 | |
UTL_RAW.CAST_TO_RAW('Content-Disposition: attachment;'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
MAKE_ATTACHED_FILE_NAME(p_file.FILE_NAME), | |
-- 添付ファイルデータはBASE64によるエンコードされていることを示す. | |
UTL_RAW.CAST_TO_RAW('Content-transfer-encoding: BASE64'), | |
UTL_RAW.CAST_TO_RAW(CRLF), | |
-- MIMEヘッダ終了 | |
UTL_RAW.CAST_TO_RAW(CRLF) | |
) | |
); | |
-- 添付ファイル出力 | |
DECLARE | |
amount BINARY_INTEGER := 768; -- 48の倍数(3と4で割り切れる数, 48バイト=64桁); | |
pos pls_integer := 1; | |
blob_len pls_integer := dbms_lob.getlength(p_file.CONTENT); | |
buf raw(1152); -- BASE64変換後のサイズ(余裕を見て読み込みバイトの1.5倍を確保) | |
BEGIN | |
WHILE pos < blob_len | |
LOOP | |
DBMS_LOB.READ(p_file.CONTENT, amount, pos, buf); | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_ENCODE.BASE64_ENCODE(buf) -- 64文字ごとに自動で改行コードが入る | |
); | |
buf := NULL; | |
pos := pos + amount; | |
END LOOP; | |
END; | |
END; | |
-- 添付ファイル終端 | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW(CRLF) | |
) | |
); | |
END LOOP; | |
-- MIME終端 | |
UTL_SMTP.WRITE_RAW_DATA( | |
vHANDLE, | |
UTL_RAW.CONCAT( | |
UTL_RAW.CAST_TO_RAW('--' || SEPARATOR || '--'), | |
UTL_RAW.CAST_TO_RAW(CRLF) | |
) | |
); | |
QUIT_MAIL(p_abort => false); | |
EXCEPTION WHEN OTHERS THEN | |
QUIT_MAIL(p_abort => true); | |
RAISE_APPLICATION_ERROR(-20120, 'メール送信に失敗しました。' || SQLERRM, TRUE); | |
END; | |
END; | |
END MAILHELPER; | |
/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DECLARE | |
P_FROM MAILHELPER.MAIL_ADDRESS; | |
P_TO MAILHELPER.MAIL_ADDRESS; | |
P_TO_LIST MAILHELPER.MAIL_ADDRESS_LIST; | |
P_SUBJECT NVARCHAR2(4000); | |
P_MESSAGE NVARCHAR2(4000); | |
P_FILES MAILHELPER.ATTACHED_FILES; | |
mes varchar2(4096); | |
rd raw(4096); | |
BEGIN | |
P_FROM.EMAIL := 'user2@localhost'; | |
P_TO.EMAIL := 'user1@localhost'; | |
P_TO_LIST(1) := P_TO; | |
P_SUBJECT := 'これはとてもながいとてもながいとてもながいとてもながいとてもながい件名'; | |
FOR x IN 1..10 LOOP | |
P_MESSAGE := P_MESSAGE || 'これは添付ありテストメールです。' || chr(10); | |
END LOOP; | |
DECLARE | |
P_FILE MAILHELPER.ATTACHED_FILE; | |
BEGIN | |
FOR cnt IN 1 .. 10 | |
LOOP | |
-- 添付ファイルデータを作成するためのバッファとして一時BLOBを作成する. | |
DBMS_LOB.CREATETEMPORARY(p_file.CONTENT, TRUE, DBMS_LOB.CALL); | |
-- 添付用テストデータ作成 | |
FOR idx IN 1..10000 | |
LOOP | |
mes := 'data-' || cnt || ': メッセージNo. ' || to_char(idx) || chr(10); | |
rd := UTL_I18N.STRING_TO_RAW(mes, 'UTF8'); | |
DBMS_LOB.WRITEAPPEND(p_file.CONTENT, UTL_RAW.LENGTH(rd), rd); | |
END LOOP; | |
p_file.CONTENT_TYPE := 'text/plain; charset=UTF-8'; | |
p_file.FILE_NAME := '添付ファイル・ダミーデータ №' || cnt || '.txt'; | |
P_MESSAGE := '添付サイズ(' || cnt || ')=' || DBMS_LOB.GETLENGTH(p_file.CONTENT) | |
|| CHR(10) || P_MESSAGE; | |
p_files(cnt) := p_file; | |
END LOOP; | |
END; | |
MAILHELPER.SENDMAIL( | |
P_FROM => P_FROM, | |
P_TO_LIST => P_TO_LIST, | |
P_SUBJECT => P_SUBJECT, | |
P_MESSAGE => P_MESSAGE, | |
P_FILES => P_FILES | |
); | |
-- 一時BLOBの解放 | |
FOR idx IN p_files.FIRST .. p_files.LAST | |
LOOP | |
DBMS_LOB.FREETEMPORARY(p_files(idx).CONTENT); | |
END LOOP; | |
END; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DECLARE | |
P_SUBJECT NVARCHAR2(200); | |
P_MESSAGE NVARCHAR2(200); | |
P_MAIL_FROM MAILHELPER.MAIL_ADDRESS; | |
P_MAIL_TO MAILHELPER.MAIL_ADDRESS; | |
P_MAIL_TO_LIST MAILHELPER.MAIL_ADDRESS_LIST; | |
BEGIN | |
P_MAIL_FROM.DESCRIPTION := '"開発用メール送信"<テスト担当>'; | |
P_MAIL_FROM.EMAIL := 'user1@localhost'; | |
P_MAIL_TO.DESCRIPTION := '開発用<1a>'; | |
P_MAIL_TO.EMAIL := 'user1@localhost'; | |
P_MAIL_TO_LIST(1) := P_MAIL_TO; | |
P_MAIL_TO.DESCRIPTION := '開発用,メール送信サーバ,テストユーザ2'; | |
P_MAIL_TO.EMAIL := 'user2@localhost'; | |
P_MAIL_TO_LIST(2) := P_MAIL_TO; | |
P_SUBJECT := 'テストメール123'; | |
P_MESSAGE := 'これは添付なしメールテストです。'; | |
MAILHELPER.SENDMAIL( | |
P_FROM => P_MAIL_FROM, | |
P_TO_LIST => P_MAIL_TO_LIST, | |
P_SUBJECT => P_SUBJECT, | |
P_MESSAGE => P_MESSAGE | |
); | |
END; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment