スポンサーリンク

PHPでGmailからメール送信する簡単なサンプルコード。PHPMailerでSMTP+TLS認証して日本語のメール本文を

PHPで簡単にメール送信するサンプルコードと,ライブラリのダウンロードの手順。

Composerは不要なので,レンタルサーバーでも楽に設置できる。

PHPMailerのダウンロード

下記ページにアクセスする。

PHPMailer/PHPMailer
https://github.com/PHPMailer/PHPMailer

右上の,緑色の「Clone or Download」を押して
ZIPでダウンロード,解凍。

PHPMailer_masterみたいな名前のフォルダが出てくるので
フォルダ名をPHPMailerにリネーム。


これを,フォルダごと
FTPなどで
レンタルサーバーにアップロードする。

メール送信のPHPコード

PHPMailerフォルダと同じ場所に,
下記のPHPファイルを設置する。

mail_test.php

実行します。<br>

<?php

// PHPでGmailでのメール送信
// https://into-the-program.com/php/phpmailer-gmail.php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require './PHPMailer/src/Exception.php';
require './PHPMailer/src/PHPMailer.php';
require './PHPMailer/src/SMTP.php';


?>

require完了。<br>


<?php

$mail = new PHPMailer(true);

?>

mail初期化。<br>


<?php

// Gmailの認証情報
$host = 'smtp.gmail.com';
$username = 'XXXXXXXXXXXXXXX@gmail.com';
$password = 'XXXXXXXXXXX';

// 差出人
$from = 'XXXXXXXXXXXXXXX@gmail.com';
$fromname = '差出人の名前';

// 宛先
$to = 'YYYYYYYYYYY@gmail.com';
$toname = '宛名';

// 件名・本文
$subject = '日本語のメール件名のテストです。';
$body = "日本語のメール本文のテストです。\n\n改行や スペースもテスト。";

// メール設定
$mail->SMTPDebug = 2; //デバッグ用に
$mail->isSMTP();

$mail->SMTPSecure = 'tls';
$mail->SMTPAuth = true;

$mail->Host = $host;
$mail->Port = 587;

$mail->Username = $username;
$mail->Password = $password;

$mail->CharSet = "utf-8";
$mail->Encoding = "base64";
$mail->setFrom($from, $fromname);

$mail->addAddress($to, $toname);
$mail->Subject = $subject;
$mail->Body    = $body;

// メール送信
if( ! $mail->send() ){
  echo '失敗: '. $mail->ErrorInfo;
}else{
  echo '成功';
}

?>

認証情報などを書き換えること。

メール送信の成功時も失敗時も,詳しいログがブラウザ上に出力される。

エラーについて

初回は下記のようなエラーログが出るはず。

実行します。
require完了。
mail初期化。
2019-08-04 16:47:09 SERVER -> CLIENT: 220 smtp.gmail.com ESMTP XXXXXXX - gsmtp
2019-08-04 16:47:09 CLIENT -> SERVER: EHLO Webサーバー名
2019-08-04 16:47:09 SERVER -> CLIENT: 250-smtp.gmail.com at your service, [XXXXXX]250-SIZE XXXXXXXX SMTPUTF8
2019-08-04 16:47:09 CLIENT -> SERVER: STARTTLS
2019-08-04 16:47:09 SERVER -> CLIENT: 220 2.0.0 Ready to start TLS
2019-08-04 16:47:10 CLIENT -> SERVER: EHLO Webサーバー名
2019-08-04 16:47:10 SERVER -> CLIENT: 250-smtp.gmail.com at your service, [XXXXXXX]250-SIZE XXXXXXX-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH250-ENHANCEDSTATUSCODES250-PIPELINING250-CHUNKING250 SMTPUTF8
2019-08-04 16:47:10 CLIENT -> SERVER: AUTH LOGIN
2019-08-04 16:47:10 SERVER -> CLIENT: 334 XXXXXXXXXX
2019-08-04 16:47:10 CLIENT -> SERVER: <credentials hidden>
2019-08-04 16:47:10 SERVER -> CLIENT: 334 XXXXXXXXXXX
2019-08-04 16:47:10 CLIENT -> SERVER: <credentials hidden>
2019-08-04 16:47:11 SERVER -> CLIENT: 534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=XXXXXXXXXXXXX XXXXXXXXXXXXXXX> PleaseXXXXXXX log in via your web browser and then try again.XXXXXXXXXXXX Learn more at XXXXXXXXX https://support.google.com/mail/answer/78754 XXXXXXXXXXX - gsmtp
2019-08-04 16:47:11 SMTP ERROR: Password command failed: XXXXXX <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=XXXXXXXXXXXXXX> PleaseXXXXXXXXXX log in via your web browser and then try again.XXXXXXXX Learn more atXXXXXXX https://support.google.com/mail/answer/78754 XXXXXXXXXXXX - gsmtp
SMTP Error: Could not authenticate.
2019-08-04 16:47:11 CLIENT -> SERVER: QUIT
2019-08-04 16:47:11 SERVER -> CLIENT: 221 2.0.0 closing connection XXXXXXX - gsmtp
SMTP Error: Could not authenticate.
失敗: SMTP Error: Could not authenticate. 

ところどころ伏字にしてある。


このエラーの原因と対処法だが,2つある。

Googleアカウントでログインして,セキュリティの項目から
「安全性の低いアプリのアクセス」をONにすること。

f:id:language_and_engineering:20190805024045p:plain

次に,PHPからのメール送信に一度失敗した後で
「セキュリティ」の中の
「最近のセキュリティ イベント」
「セキュリティイベントの確認」を開き・・・

f:id:language_and_engineering:20190805024312p:plain

そこに,
「不審なログインの試みをブロックしました」
という表示があるはずなので
そこで,このアクセスは自分だ,と入力する。

すると,数分以内に
メール送信が可能になる。

これで,らくらくメール送信できる。

CakePHPで,DBの日時タイムスタンプを,曜日と秒まで表示させる

Cakeで日時カラムから値を持ってくると,秒まで表示させるのが意外と面倒。

DB内には秒まで格納されているのに,簡単に画面上に表示させる方法がない。

下記はヘルパーメソッドの例:

  // UTCのdatetimeを受け取り,日本時間で秒まで返す。
  function getJstStringFromDatetime( $datetime_utc ){
    
    // UTC to JST
    $datetime_jst = (new \DateTime( $datetime_utc ))->setTimeZone( new \DateTimeZone('Asia/Tokyo'));
    
    // 曜日名
    $day_names = array( "日", "月", "火", "水", "木", "金", "土" );
    $day_kanji = $day_names[ $datetime_jst->format("w") ];
    
    // 秒
    $datetime_sec = date( 's', $datetime_utc->format("U") );
    
    // format: http://raining.bear-life.com/php/php%E3%81%AEdate%E9%96%A2%E6%95%B0%E3%81%A7%E6%97%A5%E4%BB%98%E3%81%AE%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E5%A4%89%E6%9B%B4
    
    return h( $datetime_jst->format("Y/n/j(${day_kanji}) H:i") . ":" . $datetime_sec );
    
  }

これで 2018/10/1(月) 12:34:56  のように表示される。

0埋めはしていない。



Datetimeクラスは頭にバックスラッシュが必要。

FuelPHPにおけるDateTimeクラスの呼び出し - てきとう
http://tmge.hatenablog.com/entry/2013/08/09/210046

  • エスケープではなく名前空間のグローバル空間です。
  • それから、Fuel の Core クラスはグローバル空間にエイリアスされるのでほとんどの場合、\Foo のように記述できます

CakePHPで,規約に従わない命名法のDBは,Scaffoldが動くことを期待するな

CakePHPの命名規約に従っていない既存DBに対して,CakeのScaffoldを動作させようとした時の苦労について。

Scaffoldは,DBの命名法が規則に従っていることを要求する

いや~,焦ったわ。

email_idというカラムがあって,これがEmailというモデルを強制的に参照してしまって,
Scaffoldが動かなかったんだわ。

カラム名の末尾の「_id」が余分で,それに対応するテーブルが存在していないということ。


ああ,外部キーを無効化したい,無視したい,解除したい。
自動的に認識させないようにしたい。
だめだな。

CAKEPHPって,規約に合ったテーブルを最初から作れない場合は,
使っちゃいけないんだ。

いい教訓になった。


unbindもできない。

        $this->unbindModel(['belongsTo' => 'Email'], false);

CAKE3では,unbindModelは削除だと。


scaffoldもCAKE特有の機能だし,規約に従っていることが動作の前提なんだろうな。

てことは,DBが規約に従ってない状態で,SCAFFOLDを動作させようとする試み自体がおかしいのだろう。

画面を自分で書こう。

対処法が見つかった

コントローラ側のFINDが問題だったわけか・・・。
containで制御するようになったから。

    public function index()
    {
        $this->paginate = [
            'contain' => ['Email', ・・・・・・]
        ];
        $callDetail = $this->paginate($this->CallDetail);

        $this->set(compact('callDetail'));
    }

containの中には,カラム名が「_id」で終わるようなカラムが一通り列挙されており,外部モデルとのリレーションを自動的にここで生成しようとしている。

containの部分を削除したら,SCAFFOLD生成コードのINDEXが動くようになった。