amtoaer

晓风残月

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

PHP form submission and automatic email sending

Recently, I found a homepage template on html5up, which has a form at the bottom. While modifying the template today, a friend mentioned that the form could be configured to automatically send email notifications upon submission. This idea sparked my interest, and I ended up spending three to four hours on it (mainly because some "tutorials" online are really misleading!). So, I’m documenting the configuration process for future reference.

Install PHP and PHP-FPM on the Server#

The author is using Ubuntu 18.04, so the commands used are:

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

Add PHP Support to the Web Server#

The author is using Nginx. To support PHP, the configuration file needs to be modified. Many tutorials online suggest changing nginx.conf, but I found that my configuration file differs significantly from theirs. After testing, I found that modifying /etc/nginx/sites-available/default worked. The PHP-related parts of the file should be modified to:

        # 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 does not allow static files to respond to POST requests, which will result in a 405 not allowed error, so the following content needs to be added
		# Port 8080 needs to be opened, or it can be modified to a currently open port (perhaps)
        error_page  405 =200 @405;
        location @405 {
            proxy_method GET;
            proxy_pass http://your_address: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):
                # Here you need to change php7.2 to the version displayed when installing 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;
        }

Modify the HTML File Containing the Form#

Next, open the HTML file containing the form and modify the form tag. For example, mine looks like this:

<!--Actually, I pasted so much just to say that the form tag needs to add action="mail.php" (just kidding)-->
<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>

Configure the mail.php File#

The form submission will call the mail.php file, so it needs to be configured next. I browsed many websites and found that there are generally only two templates online, namely this one and this one. However, after personal experience, I found that neither of them worked! The first one was purely a configuration file issue; even after I modified everything correctly, it still didn’t work (perhaps because I deleted too much?). The second one used PHP's mail() function, but unfortunately, as stated in this article that ultimately solved my problem here:

In a PHP environment, there is a function mail() for sending emails, but this function requires the server to support sendmail or to set up a mail sending server that does not require relay. However, finding a mail sending relay that does not require authentication is almost impossible, so using the mail function often fails to send emails.

The mail() function indeed cannot successfully send emails. This article also provides a solution, which is to use PHPMailer.

Clone it to the server and unzip it. The mail.php file only needs slight modifications according to the Example given in README.md. My version is roughly:

<?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;

// Change the paths of these three files to the server paths
require './PHPMailer/src/Exception.php';
require './PHPMailer/src/PHPMailer.php';
require './PHPMailer/src/SMTP.php';

// Here, change the content to correspond to the names of the items in the form tag
$email=$_POST['email'];
$name=$_POST['name'];
$message=$_POST['message'];

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

// Here I am using QQ Mail, other mail services are similar
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   = 'your_email_username';                     // SMTP username
    $mail->Password   = 'your_email_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('your_email_username', 'Nickname'); // Fill in a nickname
    $mail->addAddress('recipient_email', 'Nickname');     // Add a recipient
    
//    I don't need the following, so I commented them out
//    $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";
    
    // During testing, the content in AltBody does not appear in the email, and I am currently unclear what its use is
    $mail->AltBody = "";

    $mail->send();
    echo 'Message has been sent';
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}

Method to Submit Without Redirecting#

After the above configuration, your form should be able to send emails normally. The only downside is that after clicking submit, it redirects and shows a bunch of prompt messages, which affects the user experience. This article here provides a feasible method, which is to add a target attribute to the form tag and add an iframe tag. For my form, the form tag needs to be modified to:

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

And then add:

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

Although this modification works, it will display a simple frame after clicking submit, showing the previous redirect prompt messages. This does not achieve our goal, so I thought of hiding the iframe tag by setting its height and width to 0:

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

However, this introduces another problem: after clicking the button, it is unknown whether the email was successfully sent, as all prompt messages are hidden. So, I thought of changing the two echo statements in the original PHP file that output prompt messages to echo "<script>alert('Content')</script>", which means:

echo 'Message has been sent';
// Replace with
echo "<script>alert('Message has been sent')</script>";

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

This way, a web alert can prompt the email sending result without redirecting.

Conclusion#

Overall, while the above implementation works normally, there is still much room for improvement, such as the method for submitting without redirecting. However, since I have not systematically studied web-related knowledge, I can only make do with it for now. I’ll consider improvements when I have some free time (laughs). I also welcome everyone to give me suggestions in the comments! (By the way, does anyone actually read this article?!)

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.