Enviar correos con Gmail y PHP

correos con gmail y php
Photo by RealToughCandy.com: https://www.pexels.com/photo/php-elephant-sticker-11035390/

Una vez que ya tenemos la cuenta de servicio, ya podremos seguir con la programación. En este post veremos cómo enviar correos con Gmail y PHP.

Para este mini proyecto usaremos lo siguiente:

  • Docker
  • Composer
  • PHP
  • Archivo JSON de las credenciales de Google (este ya lo debes tener).

Primero creamos la estructura de archivos y directorios:

touch Dockerfile
touch docker-compose.yml
mkdir app
touch app/index.php

Docker

Primero vamos a construir nuestra imagen con base en php 8.2 y Apache.

Archivo Dockerfile:

# Usar la imagen base de PHP con Apache
FROM php:8.2-apache

# Instalar OpenSSL y cualquier otra extensión necesaria
RUN apt-get update && apt-get install -y libssl-dev zip unzip git \
    && docker-php-ext-install mysqli \
    && a2enmod rewrite \
    && docker-php-ext-enable mysqli

# Instalar Composer dentro del contenedor (opcional si quieres usarlo aquí)
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Configurar el directorio raíz de Apache
ENV APACHE_DOCUMENT_ROOT /var/www/html/public

# Exponer el puerto 80
EXPOSE 80

Vamos a instalar algunas dependencias, incluyendo composer y al final exponemos el puerto 80, que corresponde al puerto de http.

Ahora, para compilarlo, vamos a pasarle esto como parámetro a nuestro archivo docker-compose.yml:

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php_app
    volumes:
      - ./app:/var/www/html
    ports:
      - "8080:80"
    environment:
      - APACHE_DOCUMENT_ROOT=/var/www/html/public
    working_dir: /var/www/html
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Con esto estamos creando un volume para editar nuestros archivos en el directorio app y vamos a exponer el puerto 80 de nuestra imagen al 8080, que es el que vamos a acceder.

Ejecutamos nuestro container:

docker compose up

Instalación de librerías en composer

Conectarnos a nuestro container para usar composer e instalar las librerías que nos sirven.

Conectar al contenedor mediante bash para usar composer.

docker exec -it <nombre-del-contenedor-o-id-del-contenedor> bash

Instalar librerías:

composer require google/apiclient
composer require phpmailer/phpmailer

Una vez instaladas esas dos, podemos salir del contenedor para usar sus clases.

Script para enviar correos con Gmail y PHP

Una vez que se ha instalado todo, iremos a nuestro archivo app/index.php.

Encabezado

Iremos por partes. Primero vamos a cargar la información con autoload y llamar las clases que vamos usar:

<?php
require "vendor/autoload.php";

use Google\Client;
use Google\Service\Gmail;
use Google\Service\Gmail\Message;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

$account = "[email protected]";
$fromName = "El nombre de mi empresa";
$toEmail = "[email protected]";
$toName = "Manuel Hernandez";

$jsonConfig = "gmail.json";

Además asignamos los valores de from y to, así como el archivo JSON que descargamos cuando creamos la cuenta de servicio en Google.

PHP Mailer

PHP Mailer es la librería que nos permitirá generar el formato correcto para que las clases de Google puedan tomar el valor y enviarlo mediante sus funciones.

...

$mail = new PHPMailer();
$mail->isSMTP();
$mail->CharSet = PHPMailer::CHARSET_UTF8;

$mail->setFrom($account, $fromName);
$mail->addAddress($toEmail, $toName);
$mail->Subject = "Mi asunto";
$mail->Body = "Este es un mensaje HTML";
$mail->AltBody = "Texto plano para cuando no soporten HTML";

if (!$mail->preSend()) {
    throw new Exception("Mailer Error: " . $mail->ErrorInfo);
}
$mimeMessage = $mail->getSentMIMEMessage();

OJO: aquí no usamos PHP Mailer para enviar nada, solo construimos todo el mensaje y al final obtener el formato correcto con getSentMIMEMessage(). Podemos hacerlo sin esto, pero pa’ qué batallamos.

Cliente de Google

Ahora, con el texto ya formateado para poderlo enviar, necesitamos empezar a configurar el cliente de Google de PHP para enviar el correo.

...

$client = new Client();
$client->setAuthConfig($jsonConfig);
// scope list on vendor/google/apiclient-services/src/Gmail.php
$client->setScopes(Gmail::GMAIL_SEND);
$client->setSubject($account);

$service = new Gmail($client);

$encodedMessage = base64_encode($mimeMessage);
$encodedMessage = str_replace(["+", "/", "="], ["-", "_", ""], $encodedMessage);

$message = new Message();
$message->setRaw($encodedMessage);

try {
    $service->users_messages->send($account, $message);
    echo "Message sent successfully";
} catch (Google\Service\Exception $e) {
    echo "An error occurred: " . $e->getMessage();
} catch (Exception $e) {
    echo "An error occurred: " . $e->getMessage();
}

Claves:

  1. Primero creamos un Client de Google para poder enviar las credenciales JSON y enviarle los scopes autorizados (esto se crea en la consola de administración de Google en la delegación de autoridad de dominio). Con esto lo que hacemos es decirle a Google que tenemos todo en regla para poder comunicarnos.
  2. Luego creamos un cliente de Gmail y enviamos nuestro cliente creado y autorizado.
  3. Luego en $encodedMessage guardamos una versión en “Base64 URL-safe”, reemplazando los caracteres “+”, “/” e “=”.
  4. Creamos una instancia de Message que está dentro de Gmail (asegúrate de esto). Le enviamos nuestro mensaje codificado.

Script completo

Aquí tienes el script completo para enviar correos con Gmail y PHP.

<?php
require "vendor/autoload.php";

use Google\Client;
use Google\Service\Gmail;
use Google\Service\Gmail\Message;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

$account = "[email protected]";
$fromName = "El nombre de mi empresa";
$toEmail = "[email protected]";
$toName = "Manuel Hernandez";

$jsonConfig = "gmail.json";

// ====================> PHP MAILER <====================

$mail = new PHPMailer();
$mail->isSMTP();
$mail->CharSet = PHPMailer::CHARSET_UTF8;

$mail->setFrom($account, $fromName);
$mail->addAddress($toEmail, $toName);
$mail->Subject = "Mi asunto";
$mail->Body = "Este es un mensaje HTML";
$mail->AltBody = "Texto plano para cuando no soporten HTML";

if (!$mail->preSend()) {
    throw new Exception("Mailer Error: " . $mail->ErrorInfo);
}
$mimeMessage = $mail->getSentMIMEMessage();

// ====================> GMAIL <====================

$client = new Client();
$client->setAuthConfig($jsonConfig);
$client->setScopes(Gmail::GMAIL_SEND); // scope list on vendor/google/apiclient-services/src/Gmail.php
$client->setSubject($account);

$service = new Gmail($client);

$encodedMessage = base64_encode($mimeMessage);
$encodedMessage = str_replace(["+", "/", "="], ["-", "_", ""], $encodedMessage);

$message = new Message();
$message->setRaw($encodedMessage);

try {
    $service->users_messages->send($account, $message);
    echo "Message sent successfully";
} catch (Google\Service\Exception $e) {
    echo "An error occurred: " . $e->getMessage();
} catch (Exception $e) {
    echo "An error occurred: " . $e->getMessage();
}

Puedes ver un hilo acá si tienes algunos problemas.

En otro post lo enviaremos con Go (Golang), pa’ que tengas variedad.

¡Gracias por leer!


Posted

in

, , , ,

by