gmail callback webhook setup step by step guide

इस गाइड में आप सीखेंगे कि कैसे आप Gmail API और Google Pub/Sub का उपयोग करके अपने PHP सर्वर पर रियल-टाइम ईमेल नोटिफिकेशन सेट कर सकते हैं। जैसे ही आपके Gmail पर कोई नई मेल आती है, आपका सिस्टम उसे तुरंत पढ़कर OTP वेरिफाई कर सकता है।


🎯 यह सिस्टम क्या करता है?

  • ✅ जैसे ही आपके Gmail पर कोई नई मेल आती है, उसकी सूचना आपके सर्वर को तुरंत (Real-time) मिल जाती है।

  • ✅ आपको बार-बार Cron Job या Polling नहीं करनी पड़ती।

  • ✅ OTP (4-6 अंक) को ऑटोमैटिक रूप से निकालकर लॉग या वेरिफाई किया जा सकता है।

  • ✅ यह सिस्टम 7×24 चलता है और Cron Job से अपने आप Renew होता रहता है।


📋 पूर्व-आवश्यकताएँ (Prerequisites)

इस सेटअप को शुरू करने से पहले आपके पास ये होने चाहिए:

# चीज़ विवरण
1 Google Cloud Account एक Gmail अकाउंट जिससे आप Google Cloud Console में लॉगिन कर सकें।
2 PHP Server एक वेब सर्वर (Shared/VPS) जहाँ PHP (≥7.4) चलता हो और composer उपलब्ध हो।
3 Domain with HTTPS आपकी वेबसाइट पर SSL/HTTPS सक्षम होना चाहिए (Pub/Sub HTTP पर काम नहीं करता)।
4 Gmail Account वह Gmail ID जिस पर OTP आता है और जिसे आप मॉनिटर करना चाहते हैं।

🏗️ आर्किटेक्चर (कैसे काम करता है)

text
┌─────────────┐      ┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│             │      │             │      │             │      │             │
│   Gmail     │─────▶│  Pub/Sub    │─────▶│  Webhook    │─────▶│   OTP Log   │
│   Inbox     │      │   Topic     │      │   (PHP)     │      │   / Verify  │
│             │      │             │      │             │      │             │
└─────────────┘      └─────────────┘      └─────────────┘      └─────────────┘
      │                     │                     │                     │
      │                     │                     │                     │
      ▼                     ▼                     ▼                     ▼
  New Email        Push Notification    process_latest_email    email_content.log

🚀 चरण 1: Google Cloud Console (GCP) सेटअप

⚠️ ध्यान दें: ये सेटअप एक बार करना है। इसके बाद इसे दोबारा नहीं करना पड़ता।

1.1 API Enable करें

  1. Google Cloud Console में लॉगिन करें।

  2. एक नया Project बनाएँ (या मौजूदा Project चुनें)।

  3. API & Services > Library पर जाएँ।

  4. इन दोनों APIs को Enable करें:

    • Gmail API

    • Cloud Pub/Sub API

1.2 OAuth 2.0 Client ID बनाएँ

  1. APIs & Services > Credentials पर जाएँ।

  2. + CREATE CREDENTIALS > OAuth client ID चुनें।

  3. Application type में Web application चुनें।

  4. Name डालें (जैसे Gmail OTP Watcher)।

  5. Authorized redirect URIs में + ADD URI करके यह URL डालें:

    text
    https://yourdomain.com/project/watch_gmail.php

    (अपने असली डोमेन और फोल्डर पाथ से बदलें)

  6. CREATE बटन दबाएँ।

  7. Download JSON बटन से JSON फाइल डाउनलोड करें और उसका नाम client_secret.json रखें – इसे बाद में सर्वर पर अपलोड करना है।

1.3 Pub/Sub Topic बनाएँ

  1. Pub/Sub > Topics पर जाएँ।

  2. Create Topic पर क्लिक करें।

  3. Topic ID डालें: gmail-otp-topic

  4. बाकी सभी सेटिंग्स डिफॉल्ट पर रखें और Create करें।

1.4 ⚠️ सबसे महत्वपूर्ण: Permission देना

यह कदम भूलना सबसे बड़ी गलती है! अगर यह नहीं किया तो users.watch() कभी काम नहीं करेगा।

  1. Pub/Sub > Topics पर जाएँ।

  2. अपने gmail-otp-topic के आगे ⋮ (3 dots) > View Permissions पर क्लिक करें।

  3. Add Principal पर क्लिक करें।

  4. New Principals में डालें:

  5. Role में Pub/Sub Publisher चुनें।

  6. Save करें।

1.5 Push Subscription बनाएँ

  1. Pub/Sub > Subscriptions पर जाएँ।

  2. Create Subscription पर क्लिक करें।

  3. Subscription ID डालें: gmail-otp-subscription

  4. Topic में gmail-otp-topic चुनें।

  5. Delivery Type में Push चुनें।

  6. Endpoint URL डालें:

    text
    https://yourdomain.com/project/gmail_webhook.php
  7. Retry Policy में “Retry after exponential backoff delay” चुनें (Minimum: 10s, Maximum: 600s)।

  8. बाकी सेटिंग्स डिफॉल्ट पर रखें और Create करें।

 


📂 चरण 2: सर्वर पर PHP फाइलें सेट करें

अब आपको अपने सर्वर पर एक फोल्डर (जैसे project/) बनाकर उसमें ये फाइलें रखनी हैं।

2.1 Composer Install करें

bash
cd /path/to/your/project
composer require google/apiclient

2.2 client_secret.json अपलोड करें

Google Cloud से डाउनलोड की गई JSON फाइल को इसी फोल्डर में client_secret.json नाम से अपलोड करें।

2.3 watch_gmail.php – Watch Start / Renew

php
<?php
// watch_gmail.php - OAuth 2.0 Web Application
require_once 'vendor/autoload.php';

use Google_Client;
use Google_Service_Gmail;
use Google_Service_Gmail_WatchRequest;

// ============ कॉन्फ़िगरेशन ============
define('MY_EMAIL', '[email protected]');        // अपना Gmail ID
define('PROJECT_ID', 'your-project-id');           // Google Cloud Project ID
define('TOPIC_NAME', 'gmail-otp-topic');           // Pub/Sub Topic Name
define('CLIENT_SECRET_FILE', 'client_secret.json');
define('TOKEN_FILE', 'token.json');
// ========================================

function getClient() {
    $client = new Google_Client();
    $client->setAuthConfig(CLIENT_SECRET_FILE);
    $client->setScopes(['https://mail.google.com/']);
    $client->setAccessType('offline');
    $client->setPrompt('consent');
    return $client;
}

// 1. OAuth Callback - Code से Token बनाएँ
if (isset($_GET['code'])) {
    $code = $_GET['code'];
    $client = getClient();
    try {
        $accessToken = $client->fetchAccessTokenWithAuthCode($code);
        if (isset($accessToken['error'])) {
            throw new Exception($accessToken['error_description'] ?? 'Unknown error');
        }
        file_put_contents(TOKEN_FILE, json_encode($accessToken));
        echo "✅ Authorization Successful! Token saved.<br>";
        echo "🔄 अब आप watch_gmail.php को बिना ?code= के Run करें।";
        exit;
    } catch (Exception $e) {
        die("❌ Error: " . $e->getMessage());
    }
}

// 2. Token मौजूद है - Watch शुरू करें
if (file_exists(TOKEN_FILE)) {
    $client = getClient();
    $accessToken = json_decode(file_get_contents(TOKEN_FILE), true);
    $client->setAccessToken($accessToken);

    // Token Expire हो तो Refresh
    if ($client->isAccessTokenExpired()) {
        $refreshToken = $client->getRefreshToken();
        if ($refreshToken) {
            $newToken = $client->fetchAccessTokenWithRefreshToken($refreshToken);
            file_put_contents(TOKEN_FILE, json_encode($client->getAccessToken()));
        } else {
            unlink(TOKEN_FILE);
            header('Location: ' . filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL));
            exit;
        }
    }

    $service = new Google_Service_Gmail($client);

    try {
        $watch = new Google_Service_Gmail_WatchRequest();
        $watch->setTopicName("projects/" . PROJECT_ID . "/topics/" . TOPIC_NAME);
        $response = $service->users->watch(MY_EMAIL, $watch);
        $expiry = $response->getExpiration() / 1000;
        echo "\n✅ Watch Setup Successful!\n";
        echo "📅 Expires at: " . date('Y-m-d H:i:s', $expiry) . "\n";
        echo "🔄 इसे हर 7 दिन में Renew करें (Cron Job).\n";
    } catch (Exception $e) {
        echo "\n❌ Error: " . $e->getMessage() . "\n";
        echo "💡 अगर Error आए, तो token.json डिलीट करें और watch_gmail.php को बिना ?code= के Run करें।\n";
    }
    exit;
}

// 3. Token नहीं है - Google Login पर Redirect
$client = getClient();
$authUrl = $client->createAuthUrl();
header('Location: ' . filter_var($authUrl, FILTER_SANITIZE_URL));
exit;
?>

2.4 gmail_webhook.php – Pub/Sub Webhook Receiver

php
<?php
// gmail_webhook.php - Pub/Sub से POST पढ़े और Log करे
$logFile = __DIR__ . '/pubsub_callback_log.txt';
$rawInput = file_get_contents('php://input');
$headers = getallheaders();

$logEntry = [
    'timestamp' => date('Y-m-d H:i:s'),
    'remote_ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
    'headers'   => $headers,
    'raw_input' => $rawInput,
    'decoded'   => json_decode($rawInput, true)
];

$logLine = json_encode($logEntry, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n\n---\n\n";
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);

// OTP Processing Trigger
$data = json_decode($rawInput, true);
if (isset($data['message']['data'])) {
    $messageData = base64_decode($data['message']['data']);
    $gmailEvent = json_decode($messageData, true);
    if (isset($gmailEvent['historyId'])) {
        file_put_contents(
            __DIR__ . '/otp_trigger.log',
            date('Y-m-d H:i:s') . " - historyId: " . $gmailEvent['historyId'] . PHP_EOL,
            FILE_APPEND
        );
        // Background में process_latest_email.php चलाएँ
        shell_exec("php " . __DIR__ . "/process_latest_email.php >> /dev/null 2>&1 &");
    }
}

http_response_code(200);
echo 'OK';
?>

2.5 process_latest_email.php – Latest Email Content Reader

php
<?php
// process_latest_email.php - नवीनतम मेल का कंटेंट लॉग करें
require_once 'vendor/autoload.php';

use Google_Client;
use Google_Service_Gmail;

define('MY_EMAIL', '[email protected]');
define('TOKEN_FILE', 'token.json');
define('CLIENT_SECRET_FILE', 'client_secret.json');
define('LOG_FILE', __DIR__ . '/email_content.log');

function getGmailService() {
    $client = new Google_Client();
    $client->setAuthConfig(CLIENT_SECRET_FILE);
    $client->setScopes(['https://mail.google.com/']);
    $client->setAccessType('offline');

    if (file_exists(TOKEN_FILE)) {
        $accessToken = json_decode(file_get_contents(TOKEN_FILE), true);
        $client->setAccessToken($accessToken);
    }

    if ($client->isAccessTokenExpired()) {
        $refreshToken = $client->getRefreshToken();
        if ($refreshToken) {
            $newToken = $client->fetchAccessTokenWithRefreshToken($refreshToken);
            file_put_contents(TOKEN_FILE, json_encode($client->getAccessToken()));
        } else {
            die("❌ Refresh Token नहीं मिला।\n");
        }
    }
    return new Google_Service_Gmail($client);
}

function htmlToPlainText($html) {
    $text = strip_tags($html);
    $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    $text = preg_replace('/\s+/', ' ', $text);
    return trim($text);
}

function getEmailBody($payload) {
    $plain = ''; $html = '';
    if ($payload->getMimeType() == 'text/plain') {
        $data = $payload->getBody()->getData();
        if ($data) $plain = base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
    } elseif ($payload->getMimeType() == 'text/html') {
        $data = $payload->getBody()->getData();
        if ($data) $html = base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
    } elseif (strpos($payload->getMimeType(), 'multipart/') === 0) {
        foreach ($payload->getParts() as $part) {
            $result = getEmailBody($part);
            if ($result['plain']) $plain = $result['plain'];
            if ($result['html']) $html = $result['html'];
        }
    }
    return ['plain' => $plain, 'html' => $html];
}

$service = getGmailService();

try {
    $optParams = ['maxResults' => 1, 'q' => 'in:inbox'];
    $messages = $service->users_messages->listUsersMessages('me', $optParams);
    if (count($messages->getMessages()) == 0) {
        file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " - No new emails.\n", FILE_APPEND);
        echo "📭 Inbox empty.\n";
        exit;
    }

    $msgId = $messages->getMessages()[0]->getId();
    $message = $service->users_messages->get('me', $msgId, ['format' => 'full']);

    $subject = $from = '';
    foreach ($message->getPayload()->getHeaders() as $header) {
        if ($header->getName() == 'Subject') $subject = $header->getValue();
        if ($header->getName() == 'From') $from = $header->getValue();
    }

    $body = getEmailBody($message->getPayload());
    $plainText = $body['plain'] ?: htmlToPlainText($body['html']);

    $logContent = "========================================\n";
    $logContent .= "📅 Time: " . date('Y-m-d H:i:s') . "\n";
    $logContent .= "📩 From: " . $from . "\n";
    $logContent .= "📌 Subject: " . $subject . "\n";
    $logContent .= "📝 Body:\n" . $plainText . "\n";
    $logContent .= "========================================\n\n";

    file_put_contents(LOG_FILE, $logContent, FILE_APPEND);
    echo "✅ Email logged.\n";

} catch (Exception $e) {
    file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " - Error: " . $e->getMessage() . "\n", FILE_APPEND);
    echo "❌ Error: " . $e->getMessage() . "\n";
}
?>

🔓 चरण 3: पहली बार One-Time Activation

⚠️ यह कदम केवल पहली बार करना है। इसके बाद सब कुछ ऑटोमैटिक हो जाएगा।

3.1 ब्राउज़र से Authorization करें

  1. अपनी ब्राउज़र में यह URL खोलें:

    text
    https://yourdomain.com/project/watch_gmail.php
  2. Google Login पेज पर अपने Gmail ID से लॉगिन करें।

  3. सभी Permissions को Allow करें।

  4. “Authorization Successful! Token saved.” का मैसेज आना चाहिए।

इससे आपके सर्वर पर token.json फाइल बन जाएगी, जिसमें Refresh Token सेव है।

3.2 SSH Terminal से Watch Start करें

bash
php /path/to/your/project/watch_gmail.php

✅ आउटपुट कुछ इस तरह आना चाहिए:

text
✅ Watch Setup Successful!
📅 Expires at: 2026-09-13 14:02:40
🔄 इसे हर 7 दिन में Renew करें (Cron Job).

🗓️ चरण 4: Auto-Renew के लिए Cron Job

Gmail API Watch 7 दिन में Expire हो जाती है। इसे अपने आप Renew करने के लिए यह Cron Job लगाएँ:

bash
crontab -e

यह लाइन डालें:

bash
0 6 * * * php /path/to/your/project/watch_gmail.php >> /var/log/gmail_watch_renew.log 2>&1
  • यह हर दिन सुबह 6 बजे Watch Renew करेगा।

  • Log फ़ाइल: /var/log/gmail_watch_renew.log – इसे चेक करके Confirm करें।


🧪 चरण 5: फाइनल टेस्ट

  1. अपने Gmail ([email protected]) पर एक टेस्ट मेल भेजें।

  2. 1-2 मिनट बाद अपने सर्वर के project/ फोल्डर में ये फाइलें चेक करें:

फाइल क्या चेक करें
otp_trigger.log नई एंट्री आई – historyId लिखा होना चाहिए
email_content.log मेल का From, Subject, और Body साफ-साफ दिखना चाहिए
pubsub_callback_log.txt Google से आई पूरी POST डिटेल

अगर ये तीनों फाइलें अपडेट हुई हैं, तो आपका सिस्टम 100% काम कर रहा है! 🎉


📂 फाइलें कहाँ रखें (फोल्डर स्ट्रक्चर)

text
/public_html/project/
├── client_secret.json              # GCP से Download की गई JSON
├── token.json                      # Auto-generated (कभी Delete न करें)
├── watch_gmail.php                 # Cron वाली फाइल
├── gmail_webhook.php               # Pub/Sub Endpoint
├── process_latest_email.php        # Email Reader
├── vendor/                         # Composer Libraries
├── email_content.log               # मेल कंटेंट (Auto-generated)
├── otp_trigger.log                 # historyId Log (Auto-generated)
└── pubsub_callback_log.txt         # Pub/Sub POST Log (Auto-generated)

🆘 समस्या और समाधान (Troubleshooting)

समस्या तुरंत समाधान
Webhook पर कुछ नहीं आ रहा 1. watch_gmail.php को SSH पर Run करें → Renew हो जाएगी।
2. gmail_webhook.php को ब्राउज़र में खोलें → सिर्फ “OK” आना चाहिए।
401 Unauthenticated Error token.json Delete करें → Browser से watch_gmail.php खोलें → दोबारा Allow करें → नया token.json बनेगा।
email_content.log खाली है process_latest_email.php को SSH पर Run करें → PHP Error देखें (जैसे vendor/autoload.php न मिलना)।
Cron Job काम नहीं कर रहा cat /var/log/gmail_watch_renew.log देखें – उसमें Error लिखा होगा।
Permission Denied [email protected] को Pub/Sub Publisher Role देना न भूलें।

✅ निष्कर्ष

इस गाइड को Follow करने के बाद:

  • 🔹 आपका सिस्टम हर नई मेल को रियल-टाइम में पढ़ेगा।

  • 🔹 OTP (4-6 अंक) को ऑटोमैटिक रूप से Extract करेगा।

  • 🔹 Cron Job से Watch हर दिन Renew होती रहेगी।

  • 🔹 आपको कभी मैन्युअली कुछ नहीं करना पड़ेगा – बस एक बार Set करें और भूल जाएँ।

Leave a Reply

Your email address will not be published. Required fields are marked *