C++にて curlsmtp を使って メールを送信する
の続きです。
プログラム作成の方針
curlsmtp は日本語メールに対応していない。
対応するように改変する。
元のcurlsmtp にはなるべく手を入れず、
クラスを継承して変更する。
日本語メールの仕様
日本語などの非ASCIIの文字セットについては、 RFC2047 で規定されている。
RFC2047
MIME (Multipurpose Internet Mail Extensions) Part Three:
Message Header Extensions for Non-ASCII Text
https://www.ietf.org/rfc/rfc2047.txt
初期のインターネットは、8ビット透過ではなく、7ビットASCII文字しか通信できなかった。
そこでMIME (Multipurpose Internet Mail Extensions) が考案された。
バイナリデータは、Base64などの形式でASCII文字列に変換する方式になった。
日本語のメール本文
日本語テキストはバイナリデータとして扱い Base64 形式でASCII文字列に変換する。
元の文字セット (UTF-8)とBase64形式で変換(エンコード)したことを示す2つのヘッダーを追加する。 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: base64
ヘッダー部とメール本文は空行(CRLF)で区切る。
UTF-8 か ISO−2022-JP が一般的。 文字セット(charset) は、IANAでは多くの文字セットが定義されている。
IANA (Internet Assigned Numbers Authority) 文字セット https://www.iana.org/assignments/character-sets/character-sets.xhtml
変換(エンコード)方式は、Base64 が一般的。 RFC2045 では、Base64 の他に、Quoted-Printable も規定されている。
参考: 日本語メールの仕組み
https://sendgrid.kke.co.jp/blog/?p=10958
日本語のメールヘッダー
元の文字セット(UTF-8)とbase64形式で変換(エンコード)したことを示す2つの情報を含めて下記の形式で1つASCII文字列にする。 =?文字セット?エンコード方式?エンコード後の文字列?=
文字セットには、メール本文と同様「UTF-8」という値が入る。 エンコード方式には、B」(Base64)か「Q」(Quoted-Printable)のいずれかの値が入る。
日本語メールの文字セット
歴史的な理由で 7ビットコードである ISO−2022-JP が使われている。
近年は、多くの環境で 標準の文字セットをUTF-8 にしているので、UTF-8で問題ない。
プログラムで ISO−2022-JP を扱うためには、
icu4c などの多言語ライブラリを使用する必要があり、手間が増える。
Windows パソコンで使われている Shit-JIS は、
対応しているメールアプリもあるが、使わないほうが無難。
curlsmtp の改変
日本語用のAPIを追加する
void CurlSmtp2::set_subject_charset( const std::string subject, const std::string charset ) { std::string b64; base64encode( subject, b64 ); m_subject_b64.assign( b64 ); m_subject_charset.assign( charset ); } void CurlSmtp2::set_message_charset( const std::string msg, const std::string charset ) { std::string b64; base64encode( msg, b64 ); m_msg_b64.assign( b64 ); m_msg_charset.assign( charset ); }
make_send_message2()を改変する
// subject header if( !m_subject_b64.empty() && !m_subject_charset.empty() ) { snprintf(buf, BUFSIZE, SUBJECT_CHARSET_FORMAT, (char *)m_subject_charset.c_str(), (char *)m_subject_b64.c_str() ); } else { snprintf(buf, BUFSIZE, SUBJECT_FORMAT, (char *)subject_.c_str() ); } // message if( !m_msg_b64.empty() && !m_msg_charset.empty() ) { // header snprintf(buf, BUFSIZE, CONTENT_TYPE_CHARSET_FORMAT, (char *)m_msg_charset.c_str() ); send_buffer_.push_back( buf ); send_buffer_.push_back( CONTENT_TRANSFER_BASE64 ); // split body send_buffer_.push_back(ENTER); send_buffer_.push_back( m_msg_b64 ); } else { // split body send_buffer_.push_back(ENTER); send_buffer_.push_back(message_ + ENTER); }
全体のコードは、githubに公開した。 https://github.com/ohwada/MAC_cpp_Samples/tree/master/curlsmtp2