Formularz kontaktowy powiązany z Google Gmail SMTP

Pokażę jak można stworzyć prosty formularz kontaktowy na naszej stronie domowej obsługujący SMTP Google Gmaila, PHPMailer bazujący na hostingu lub początkowo na własnym serwerze Apache z obsługą PHP.
Czyli, formularz kontaktowy, który stworzymy będzie przy pomocy PHPMailer-a wysyłał nam na konto Google Gmail dane z tego formularza w postaci nowych emaili.

Zanim opiszę kolejne kroki wykonania, krótka finalna prezentacja.

Oraz wygląd wysłanej wiadomości:

To już wiemy czego możemy oczekiwać, a teraz środowisko w którym będziemy pracować.
Wszystko będzie postawione na serwerze Apache z PHP. Skorzystać można z gotowego zestawu XAMPP lub też samemu oddzielnie postawić serwer z PHP.

Dobrze, teraz tworzymy jakiś katalog w folderze publicznym www, a wewnątrz plik index.html, css, js oraz konfigurujemy w utworzonym pliku html formularz kontaktowy. Tu z polami: name, email, message. Można dodawać inne lub też dowolnie konfigurować.
Załączam plik webowy:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Contact form</title>
    <!-- Bootstrap CSS -->
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom CSS -->
    <link href="styles.css" rel="stylesheet">
</head>
<body>

    
<!-- Contact Section -->
<section id="contact" class="bg-light py-5">
    <div class="container">
        <h2 class="text-center mb-4">Contact</h2>
        <form action="contact.php" method="post">
          <div class="form-group">
              <label for="name">Name</label>
              <input type="text" class="form-control" id="name" name="name" placeholder="Your Name" required>
          </div>
          <div class="form-group">
              <label for="email">Email address</label>
              <input type="email" class="form-control" id="email" name="email" placeholder="Your Email" required>
          </div>
          <div class="form-group">
              <label for="message">Message</label>
              <textarea class="form-control" id="message" name="message" rows="3" placeholder="Your Message" required></textarea>
          </div>
          <button type="submit" class="btn btn-primary">Send</button>
      </form>
      
    </div>
</section>

<!-- Bootstrap and JavaScript -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="scripts.js"></script>
</body>
</html>

W znajdującym się obecnie katalogu instalujemy composer z linii poleceń:

sudo apt get install composer

W końcowym rezultacie utworzony plik composer.json musi mieć odpowiednio taką zawartość jak poniżej:

{
    "require": {
        "phpmailer/phpmailer": "^6.9",
        "google/apiclient": "^2.17",
        "league/oauth2-client": "^2.7",
        "league/oauth2-google": "^4.0"
    }
}

Teraz tworzymy poprzez konto Gmail nowy Google Cloud Project.
I tak:
stan publikacji – ustawiamy na wersję produkcyjną
Musimy pamiętać, żeby zaznaczyć dane logowania OAuth 2.0 jako Web application
URI przekierowania powinny być następujące:
-http://localhost/callback.php
-http://127.0.0.1/callback.php
Otrzymujemy w wyniku procesu utworzenia projektu:
-identyfikator klienta
-tajny klucz klienta
-stan powinien być włączony

Powinniśmy również zainstalować:

composer require phpmailer/phpmailer

composer require google/apiclient

W celu otrzymania refresh-tokenu wywołujemy plik get_refresh_token.php:

php get_refresh_token.php

Niezbędne będzie utworzenie następujących dwóch plików php:

// get_refresh_token.php
<?php
require 'vendor/autoload.php';

$client = new Google_Client();
$client->setClientId('tu wstawiamy id klienta z cloud projektu');
$client->setClientSecret('tutaj wstawiamy tajny klucz klienta');
$client->setRedirectUri('http://localhost/callback.php');
$client->addScope('https://mail.google.com/');
$client->setAccessType('offline');
$client->setPrompt('consent');

// Generate the URL for the consent screen
$authUrl = $client->createAuthUrl();
echo "Please visit this URL to authorize the application: " . $authUrl . "\n";

// After authorization, Google will redirect to your callback URL with a code
// You need to exchange this code for tokens
echo "Enter the code you received: ";
$authCode = trim(fgets(STDIN));

// Exchange the auth code for tokens
$token = $client->fetchAccessTokenWithAuthCode($authCode);

if (isset($token['refresh_token'])) {
    echo "Refresh Token: " . $token['refresh_token'] . "\n";
} else {
    echo "No refresh token received. Make sure you've set access type to offline and prompted for consent.\n";
}
?>

Oraz:

// callback.php
<?php
require 'vendor/autoload.php';

$client = new Google_Client();
$client->setClientId('nasz identyfikator klienta');
$client->setClientSecret('tajny klucz klienta');
$client->setRedirectUri('http://localhost/callback.php');

if (isset($_GET['code'])) {
    $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
    $client->setAccessToken($token);

    // Check if we have a refresh token
    if (isset($token['refresh_token'])) {
        $refresh_token = $token['refresh_token'];
        echo "Refresh Token: " . $refresh_token;
        // Here you would typically save this refresh token securely for future use
    } else {
        echo "No refresh token received.";
    }
} else {
    echo "No authorization code received.";
}
?>

Będzie nam jeszcze potrzebny refresh_token. A to oto sposób na jego uzyskanie:

php get_refresh_token.php

Wszystkie pliki powinny znajdować się w tej samej lokalizacji.

Teraz możemy zająć się tworzeniem głównego pliku PHP – > contact.php odpowiedzialnego za korzystanie z providera Google, PHPMailera i wysyłanie emaila na nasze konto pocztowe.

Poniżej plik contact.php:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

require_once 'vendor/autoload.php';

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\OAuth;
use League\OAuth2\Client\Provider\Google;

// Stała konfiguracja
$config = [
    'client_id' => 'tu umieszczamy nasze id klienta',
    'client_secret' => 'tajny klucz klienta',
    'refresh_token' => 'utworzony przez nas refresh_token',
    'gmail_address' => 'nasza nazwa konta gmail'
];

// Sprawdź, czy dane formularza zostały przesłane
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // Pobierz dane z formularza
    $sender_name = $_POST['name'] ?? '';
    $sender_email = $_POST['email'] ?? '';
    $message = $_POST['message'] ?? '';

    $mail = new PHPMailer(true);

    try {
        // Konfiguracja OAuth2
        $provider = new Google([
            'clientId' => $config['client_id'],
            'clientSecret' => $config['client_secret'],
        ]);

        // Wyłącz wyświetlanie logów SMTP
        $mail->SMTPDebug = SMTP::DEBUG_OFF;
        $mail->isSMTP();
        $mail->Host = 'smtp.gmail.com';
        $mail->Port = 587;
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
        $mail->SMTPAuth = true;
        $mail->AuthType = 'XOAUTH2';

        $mail->setOAuth(
            new OAuth([
                'provider' => $provider,
                'clientId' => $config['client_id'],
                'clientSecret' => $config['client_secret'],
                'refreshToken' => $config['refresh_token'],
                'userName' => $config['gmail_address'],
            ])
        );

        // Konfiguracja wiadomości
        $mail->setFrom($config['gmail_address'], 'Contact form');
        $mail->addAddress($config['gmail_address'], 'Your name');
        $mail->Subject = "New message from $sender_name";
        $mail->Body    = "You received a new message from:\n\n";
        $mail->Body   .= "Name: $sender_name\n";
        $mail->Body   .= "Email: $sender_email\n\n";
        $mail->Body   .= "Message:\n$message";

        $mail->send();
        echo '<p style="color: green;">Your message has been sent successfully. Thank you for contacting us!</p>';
    } catch (Exception $e) {
        echo '<p style="color: red;">An error occurred while sending the message. Please try again later.</p>';
        error_log("Sending email failed: " . $mail->ErrorInfo . "\n" . $e->getMessage());
    }
} else {
    // Wyświetl formularz, jeśli nie został jeszcze przesłany
    include 'form.html';
}
?>

I na tym kończąc powinniśmy mieć rezultat jak pokazany na samym początku tego posta.