ログ日記

作業ログと日記とメモ

Haskellでメール送信

Google グループ
メールは HaskellNet を使うといいよ、と書かれている。
Author Jun Mukai って入門Haskellの著者かな?

cabal install iconv --global
cabal install HaskellNet --global

ソースをDLしてきて example/smtp.hs の通りにすれば英語のメールは送信できた。
しかし日本語が…。
Text.Mime.showMessage はFromやToをMimeエンコードしてくれるのだが、値の全てをエンコードするようになっている。

To: =?ISO-2022-JP?b?〜〜〜?= <user@example.com>

こうなってほしいところだが

To: =?ISO-2022-JP?b?〜〜〜〜メールアドレスもここ〜〜〜?=

こういう動作になっている。
この動作だとメールサーバがホスト名を判別できずに

To: =?ISO-2022-JP?b?〜〜〜〜@example.comが見えない〜〜〜?=@example.com

と後ろにホスト名がくっついて送信された。


あとiso-2022-jpに変換するためにconvert関数を使おうと思ったが、convert関数を使うためには Data.ByteString.Lazy.Char8 を使わないといけない?だけれどHaskellNetのメール送信は Data.ByteString.Char8 を使うようなので若干面倒なことに。


なんかやり方か使いどころが間違ってるのかもわからんが、行き当たりばったりな感じで書いてみた。

import HaskellNet.SMTP (connectSMTP, sendMail, closeSMTP)
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as LBS
import Codec.Text.IConv (convert)
import Codec.Binary.UTF8.String (encodeString)
import Text.Mime (showMessage, b64Encode)

smtpServer = "localhost"
sendFrom   = "user1@example.com"
sendTo     = "user2@example.com"
headerFrom = b64Header "\"テストプログラムからの日本語文字テスト送信\"" ++ "<" ++ sendFrom ++ ">"
headerTo   = b64Header"\"宛先ユーザ\"" ++ "<" ++ sendTo ++ ">"
charset    = "ISO-2022-JP"

main = do
   con <- connectSMTP smtpServer
   sendMail sendFrom [sendTo] (BS.pack $ show $ showMessage charset msg) con
   closeSMTP con

msg = ([("From", headerFrom)
       ,("To", headerTo)
       ,("Content-Type", "text/plain; charset=" ++ charset)
       ,("Subject", b64Header "Test 日本語メールテスト、エンコード後に改行あり")],
       BS.pack (toCharset "\r\nhaskellnet のメール送信。\r\n."))

b64Header :: String -> String
b64Header s = "=?" ++ charset ++ "?b?" ++ b64Encode (toCharset s) ++ "?="

toCharset = LBS.unpack . convert "UTF-8" charset . LBS.pack . encodeString

pack、unpackが冗長な気がしてならないが、取り敢えずこれで正しいフォーマットで送れた。
encodeStringとかまだよく分かっていない。


ローカルから別のサーバーにメールを送る場合だと文字列をエンコードさえすればあとはpopen的なものを使ってsendmailに渡せばいいわけだから、無駄なことを色々やってる気がする。
しかしHaskellプログラムからメールを送信するための情報がどこにあるか分からん…。