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">Name</label>
            <input type="text" name="name" id="name" />
        </div>
        <div class="field half">
            <label for="email">Email</label>
            <input type="text" name="email" id="email" />
        </div>
        <div class="field">
            <label for="message">Message</label>
            <textarea name="message" id="message" rows="6"></textarea>
        </div>
    </div>
    <ul class="actions">
        <li><input type="submit" value="Send Message" class="primary" /></li>
        <li><input type="reset" value="Clear" /></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 = "An E-mail from $email";
    $mail->Body = "This e-mail is written by $name : $message";
    
    // 我在测试时,AltBody中的内容并不会在邮件中显示出来,目前暂时不清楚有什么用
    $mail->AltBody = "";

    $mail->send();
    echo 'Message has been sent';
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$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 'Message has been sent';
// 替换为
echo "<script>alert('Message has been sent')</script>";

echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
// 替换为
echo "<script>alert('Message could not be sent.')</script>";

这样的话就可以实现网页弹窗提示邮件发送结果而不跳转了。

结语#

总体来说,以上实现方式虽然可以正常使用,但是还有很大改进空间,比如提交不跳转的实现方式。不过毕竟自己没有系统学习过 web 方面的知识,也只能得过且过了。等什么时候能闲下来再考虑改进吧(笑)。也欢迎大家在评论里给我提建议吖!(话说这篇文章真的有人看吗?!)

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。