レンタルサーバ上のPythonからメールを送信しようとしたら、Client host rejectedになった

SSHの使えないレンタルサーバにて、Pythonからメールを送信しようとしたらClient host rejectedエラーが出たため、対応をメモしておきます。

 

環境

レンタルサーバ

   

開発環境

 

状況

開発環境で以下のようなPythonスクリプトを書いて実行してみたところ、メールを送信することができました。

msg = MIMEText(email_body, 'plain', 'utf-8')
msg['Subject'] = Header(u'メールテスト', 'utf-8')
msg['From'] = SENDER_ADDRESS
msg['To'] = ','.join(RECIEVER_ADDRESSES)

charset.add_charset('utf-8', charset.SHORTEST, None, 'utf-8')

smtp_client = smtplib.SMTP(SENDER_DOMAIN, 587)
smtp_client.sendmail(SENDER_ADDRESS, RECIEVER_ADDRESSES, msg.as_string())
smtp_client.quit()

 
その後、レンタルサーバへアップロードして試してみたところ、

{u'sender@example.com': (554, '5.7.1 : Client host rejected: Access denied')}

のようなエラーが出て、メールを送信できませんでした。

 

対応

SMTPの587ポート(サブミッションポート)で送信するため、レンタルサーバ上ではSMTP-AUTHなどができていないのかなと考えました。そこで、以下の2通りの方法での送信を試してみました。

 

smtplibでログインアカウントとパスワードを渡す方法

Pythonのドキュメントを参考にしてsmtplib.login()を使用してみたところ、メールの送信ができました。
20.12. smtplib — SMTP プロトコルクライアント — Python 2.7ja1 documentation

smtp_auth_client = smtplib.SMTP(SENDER_DOMAIN, 587)
smtp_auth_client.login(SENDER_LOGIN_ID, SENDER_PASSWORD)
smtp_auth_client.sendmail(SENDER_ADDRESS, RECIEVER_ADDRESSES, msg.as_string())
smtp_auth_client.quit()

 

レンタルサーバ上のsendmailを叩く方法

上記の方法だとSMTPサーバーを使うIDとパスワードをPythonスクリプト内に埋める必要があるため、少し不安でした。

レンタルサーバのドキュメントを読んでみたところ、sendmailが使えそうでした。

そのため、以下を参考に、Pythonsubprocessモジュールを使って、Pythonからsendmailを叩くことにしました。
email - Sending mail via sendmail from python - Stack Overflow

msg = MIMEText(email_body, 'plain', 'utf-8')
msg['Subject'] = Header(u'メールテスト', 'utf-8')
msg['From'] = SENDER_ADDRESS
msg['To'] = ','.join(RECIEVER_ADDRESSES)

charset.add_charset('utf-8', charset.SHORTEST, None, 'utf-8')

p = Popen(["/usr/sbin/sendmail", "-t", "-oi"], stdin=PIPE)
p.communicate(msg.as_string())

こちらもメールを送信することができました。

 

ソースコード

GitHubに上げました(mail.py, mail.html)。再現しやすいよう、Bottleでフォームを作っています。
thinkAmi-sandbox/Bottle-sample

 

参考

メールまわり

 

ヒアドキュメントまわり