amtoaer

晓风残月

叹息似的渺茫,你仍要保存着那真!
github
x
telegram
steam
nintendo switch
email

php表單提交並自動發送郵件

最近在html5up上淘了個首頁模板,模板底有一個表單,今天在修改模板的時候,朋友提起可以配置表單實現提交表單時自動發送郵件通知,於是就萌生了這個想法,結果沒想到一搞就是三四個小時(主要是因為網上的某些 “教程” 太坑人了!),所以記錄一下配置過程給後來人參考。

給伺服器安裝 php,php-fpm#

作者使用的是 ubuntu18.04,所以使用

sudo apt-get install php
sudo apt-get install php-fpm

web 伺服器添加 php 支持#

作者使用的是 nginx,為支持 php 需要修改一下配置文件,網上不少教程說要改nginx.conf,但我發現我這裡的配置文件和他們的有很大差異,後來實測修改/etc/nginx/sites-available/default有效。將文件與 php 有關部分修改為:

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html index.php;

        server_name _;
        
		# nginx不允許靜態文件響應post請求,會出現405 not allowed提示,所以需要添加以下內容
		# 需要開啟8080端口,或者可以修改為目前已經開啟的端口(或許)
        error_page  405 =200 @405;
        location @405 {
            proxy_method GET;
            proxy_pass http://你的地址:8080;
        }

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        # pass PHP scripts to FastCGI server
        #
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;

                # With php-fpm (or other unix sockets):
                # 這裡需要把php7.2修改為安裝php時顯示的版本
                fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
                # With php-cgi (or other tcp sockets):
                # fastcgi_pass 127.0.0.1:9000;
        }

修改表單所在的 html 文件#

接下來打開表單所在的 html 文件,修改 form 標籤,例如我的:

<!--其實粘貼這麼多只是想說form標籤需要加個action="mail.php"啦(滑稽)-->
<form method="post" action="mail.php">
    <div class="fields">
        <div class="field half">
            <label for="name">姓名</label>
            <input type="text" name="name" id="name" />
        </div>
        <div class="field half">
            <label for="email">電子郵件</label>
            <input type="text" name="email" id="email" />
        </div>
        <div class="field">
            <label for="message">訊息</label>
            <textarea name="message" id="message" rows="6"></textarea>
        </div>
    </div>
    <ul class="actions">
        <li><input type="submit" value="發送訊息" class="primary" /></li>
        <li><input type="reset" value="清除" /></li>
    </ul>
</form>

配置 mail.php 文件#

form 提交將會調用 mail.php 文件,接下來就需要配置它了。我瀏覽了許多網站,發現網上大體只有兩個模板,即這個這個。但親身體驗後發現都!不!能!用!第一個是單純的配置文件問題,我把各項修改好後還是不能用。(或許是因為我多刪了點東西?)第二個則使用了 php 的 mail () 函數,不過很不幸的是,正如這篇最後解決我問題的文章中寫的一樣:

PHP 環境下,是提供了發送郵件的函數mail()的,不過該函數要求伺服器支持 sendmail 或者必須設置一台不需要中繼的郵件發送伺服器,但現在要找到一台不需要身份驗證的郵件發送中繼幾乎不可能,所以使用 mail 函數往往無法成功發送電子郵件。

mail () 函數確實無法成功發送郵件。這篇文章同樣給出了一個解決辦法,就是使用PHPMailer

將其git clone到伺服器並解壓,mail.php 只需按照 README.md 中所給的 Example 進行微量修改,我的大概為:

<?php
// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

// 修改這三個文件的路徑為伺服器路徑
require './PHPMailer/src/Exception.php';
require './PHPMailer/src/PHPMailer.php';
require './PHPMailer/src/SMTP.php';

// 這裡將內容對應改成form標籤中各項的名字
$email=$_POST['email'];
$name=$_POST['name'];
$message=$_POST['message'];

// Instantiation and passing `true` enables exceptions
$mail = new PHPMailer(true);

// 這裡我使用的是qq郵箱,其它郵箱同理
try {
    //Server settings
    $mail->SMTPDebug = SMTP::DEBUG_SERVER;                      // Enable verbose debug output
    $mail->isSMTP();                                            // Send using SMTP
    $mail->Host       = 'smtp.qq.com';                    // Set the SMTP server to send through
    $mail->SMTPAuth   = true;                                   // Enable SMTP authentication
    $mail->Username   = '郵箱的用戶名';                     // SMTP username
    $mail->Password   = '郵箱的密碼';                               // SMTP password
//    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;         // Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` also accepted
    $mail->SMTPSecure = 'ssl';
    $mail->Port       = 465;                                    // TCP port to connect to

    //Recipients
    $mail->setFrom('郵箱的用戶名', '隨便填個暱稱');
    $mail->addAddress('發送到的郵箱', '隨便填個暱稱');     // Add a recipient
    
//	後邊的那些我不用,就註釋掉了
//    $mail->addAddress('ellen@example.com');               // Name is optional
//    $mail->addReplyTo('info@example.com', 'Information');
//    $mail->addCC('cc@example.com');
//    $mail->addBCC('bcc@example.com');

    // Attachments
//    $mail->addAttachment('/var/tmp/file.tar.gz');         // Add attachments
//    $mail->addAttachment('/tmp/image.jpg', 'new.jpg');    // Optional name

    // Content
    $mail->isHTML(true);                                  // Set email format to HTML
    $mail->Subject = "來自 $email 的郵件";
    $mail->Body = "$name 寫的這封郵件 : $message";
    
    // 我在測試時,AltBody中的內容並不會在郵件中顯示出來,目前暫時不清楚有什麼用
    $mail->AltBody = "";

    $mail->send();
    echo '郵件已發送';
} catch (Exception $e) {
    echo "郵件無法發送. 郵件發送錯誤: {$mail->ErrorInfo}";
}

提交不跳轉方法#

經過以上配置之後,你的表單應該可以正常發送郵件了,唯一的不足是在點擊提交之後會跳轉出現一堆提示信息,影響觀感,這篇文章中給出了一種可行方法,即為form標籤加入 target 屬性並添加iframe標籤。以我的表單為例,需要將form標籤修改為:

<form method="post" action="mail.php" target="id_iframe">

並在其後添加:

<iframe id="id_iframe" name="id_iframe" style=""></iframe>

這樣修改雖然有效,但會在點擊提交之後出現一個簡陋的框體,其中顯示的內容就是之前跳轉後的提示信息。這沒有達到我們的目的,於是想到將iframe標籤隱藏,也就是將其的高度和寬度設置為 0:

<iframe id="id_iframe" name="id_iframe" style="" width="0" height="0"></iframe>

可這樣又會出現一個問題,點擊按鈕之後郵件到底有沒有發送成功是未知的,那該怎麼辦呢?我想到的是,將原來 php 文件中的兩個用於輸出提示信息的echo修改成echo "<script>alert('內容')</script>",也就是:

echo '郵件已發送';
// 替換為
echo "<script>alert('郵件已發送')</script>";

echo "郵件無法發送. 郵件發送錯誤: {$mail->ErrorInfo}";
// 替換為
echo "<script>alert('郵件無法發送.')</script>";

這樣的話就可以實現網頁彈窗提示郵件發送結果而不跳轉了。

結語#

總體來說,以上實現方式雖然可以正常使用,但是還有很大改進空間,比如提交不跳轉的實現方式。不過畢竟自己沒有系統學習過 web 方面的知識,也只能得過且過了。等什麼時候能閒下來再考慮改進吧(笑)。也歡迎大家在評論裡給我提建議吖!(話說這篇文章真的有人看嗎?!)

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。