忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2017/10/19 23:44 |
PHP1-28:XAMPPでメール

XAMPP環境でいきなり
mail($mail_to,$mail_subject,$mail_message,$mail_headers);
と書いてもメールを送信することは出来ません。
以下のようなエラーが返ってきます。

Warning: mail() [function.mail]: Failed to connect to mailserver at "localhost" port 25

PHPのメール関数は、自力でメールを送信するわけではなくSMTPサーバというメール処理プログラムに処理を預けています。
OutlookExpressやBeckyといったWindows用のメーラは、プロバイダにあるSMTPサーバに接続してメールの送受信を行っていますが、PHPのメール関連関数も同じです。
要するに、そこらへんの設定を行わなければなりません。

XAMPPには最初からMercuryというSMTPサーバが付属していますが、デフォルトでは無効になっています。
設定が甘いと不正メール中継の踏み台にされたりするからです。
また、MercuryはHTTPサーバ機能も持っているためApacheと干渉したりするので面倒な部分もあります。
OutlookExpressのように、手っ取り早く外部SMTPサーバを使って解決してしまいましょう。
今回対象とするサーバはGoogleGmailです。
GmailはSMTP_AuthおよびSSLが必須でありセキュリティ的にも丈夫です。

さて、そうすると本来ならfsockopenやらを使用して外部SMTPサーバに接続してにょろにょろといったことを行わないといけないのですが、そこらへんを自力でどうにかするのはとても大変です。
単純な送信程度ならまだしも、うっかり添付ファイルを送信したいなあとか考えてしまうと速攻行き詰まります。
メールのフォーマットは歴史的経緯もあり非常に複雑怪奇なものとなっており、自力での実装は正直無理だろこれ。
http://www.atmarkit.co.jp/fnetwork/rensai/netpro03/netpro01.html
http://www.atmarkit.co.jp/fnetwork/rensai/netpro04/netpro01.html
ましてやSSLやらSMTP-Authやらが入ってきた日にはもう何が何だか。

というわけで例によってPearを利用してGmailに接続してみます。

Mail 1.2.0b1 (beta)
http://pear.php.net/package/Mail
Net_SMTP 1.3.1 (stable)
http://pear.php.net/package/Net_SMTP
Net_Socket 1.0.9 (stable)
http://pear.php.net/package/Net_Socket/

Pear::MailをMailフォルダに、Net_SMTPとNet_SocketをNetフォルダに格納します。
そしてさっそくラッパクラス。
 
gmail.class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
    //初期設定
    define('PEAR_DIR',$_SERVER['DOCUMENT_ROOT'].'/src/php/pear/');
    ini_set('include_path',PEAR_DIR.PATH_SEPARATOR.ini_get('include_path'));
    require_once(PEAR_DIR.'Mail/Mail.php');
    
    class pearGMailModel{
        //メンバ変数
        private $params= array(
            'host'     => 'tls://smtp.gmail.com',
            'port'     => 465,
            'auth'     => true,
            'debug'    => false,
            'username' =>'',
            'password' =>''
        );
        private $headers = array(
            'To'=>'',
            'From'=>'',
            'Subject'=>''
        );
        private $mailto='';
        private $body = '';
        
        //コンストラクタ
        public function __construct($debug=null){
            mb_internal_encoding('UTF-8');
            if($debug=='debug'){$this->params['debug']=true;}
        }
        
        //ユーザ情報
        public function setUser($user,$pass){
            $this->params['username']=$user;
            $this->headers['From']=$user;
            $this->params['password']=$pass;
        }
        
        //メール内容
        public function setMail($subject,$body){
            //ヘッダはISO-2022-JP+mimeエンコード
            $this->headers['Subject']
            =mb_encode_mimeheader($subject,'ISO-2022-JP');
            //本文はISO-2022-JP
            $this->body=mb_convert_encoding
            ($body,'ISO-2022-JP', mb_detect_encoding($body));
        }
        
        //宛先
        public function setAddress($mailto){
            $this->mailto=$mailto;
            $this->headers['To']=$mailto;
        }
        
        //送信
        public function send(){
            if($this->_checkParam()===false){return false;}
            $smtp=Mail::factory('smtp', $this->params);
            return $smtp->send($this->mailto, $this->headers, $this->body);
        }
        
        //パラメータチェック
        public function _checkParam(){
            if(!$this->mailto 
                || !$this->body
                || !$this->params['username']
                || !$this->params['password']
                || !$this->headers['To']
                || !$this->headers['From']
                || !$this->headers['Subject']
            ){return false;}
            return true;
        }
        
    #↓クラスのおわり
    }

mb_encode_mimeheaderは恐ろしいことに文字コードを勝手に変更してしまいます。
変換後の文字コードはmb_encode_mimeheaderの2番目の引数が使われますが、変換元の文字コードは指定することが出来ず、mb_internal_encodingで指定したものが使われます。
ここらへんがmb_encode_mimeheaderに関する誤解と混乱の元となっているのですがまあいいや。

今回は直接mb_internal_encodingをコンストラクタで指定しています。
本当に正確を期するならmb_internal_encodingもmb_encode_mimeheaderもsendメソッド内で行い、最後はmb_internal_encodingを元に戻すべきなのですが、これもまあいいや。
基本的にUTF-8で統一していれば問題はありません。

使用する場合は以下のように。

gmail.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
    //初期設定
    header("Content-type: text/html; charset=utf-8");
    require_once('./gmail.class.php');
    
    //ユーザ情報
    $mail_user='ユーザ名';
    $mail_pass='パスワード';
    
    //メールの内容
    $mail_to='宛先';
    $mail_subject='件名';
    $mail_body='本文';
    
    //送信
    $gmail = new pearGMailModel('debug');
    $gmail->setUser($mail_user,$mail_pass);
    $gmail->setAddress($mail_to);
    $gmail->setMail($mail_subject,$mail_body);
    
    $ret=$gmail->send();

以上で自分のGMailアカウントからメールが送信されたはずです。
めでたし。
PR


2008/09/29 19:40 | Comments(1) | TrackBack(0) | PHP

トラックバック

トラックバックURL:

コメント

ただこれ問題点?として、
CAの証明書貰ってないはずなのに普通に送信できてるので、
本当に暗号化できてるんだろうか?的疑問が

あとURLに↓の形式が入らない
http://itpro.nikkeibp.co.jp/article/COLUMN/20060731/244715/?ST=security&P=2
posted by 名無しさん必死だな at 2008/09/30 12:15 [ コメントを修正する ]

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<PHP1-29:WYSIWYGなHTMLエディタ | HOME | PHP1-27:QRコードを作ってみる >>
忍者ブログ[PR]