Apps Script سے Google Sheets کانٹیکٹس Brevo میں امپورٹ کریں

بار بار چلنے والی Apps Script مثال جو رضامندی چیک کرتی، فیلڈز ملاتی، ان سبسکرائب بچاتی اور API خرابی دکھاتی ہے۔

google apps script brevo

مختصر جواب کیا ہے؟

Sheet میں email، firstName، lastName اور consent کالم بنائیں۔ BREVO_API_KEY کو Script Properties میں رکھیں، کوڈ میں لسٹ ID دیں اور syncSheetToBrevo چلائیں۔ صرف رضامندی والی قطاریں دیکھی جاتی ہیں؛ اسکرپٹ Brevo میں ان سبسکرائب چیک کرتا، ڈپلیکیٹ ہٹاتا اور API خرابی پر رک جاتا ہے۔ یہ آپ کی ذمہ داری کا Apps Script ہے، اندرونی کنیکٹر نہیں۔

مزید جانیں
اس صفحہ پر

کسی تقریب کے بارہ اندراج ایک بار ایکسپورٹ کرنا آسان ہے۔ دوسری بار ایک ای میل دوہر سکتی ہے اور دوسرا شخص Brevo میں ان سبسکرائب ہو چکا ہو سکتا ہے۔ بار بار چلنے والا امپورٹ دونوں باتیں دیکھے۔

اسکرپٹ Brevo کے کانٹیکٹ پڑھنے، بنانے اور اپ ڈیٹ کرنے والے اینڈ پوائنٹس استعمال کرتا ہے۔ یہ چھوٹے مقررہ امپورٹ کے لیے ہے، بڑی لوڈنگ یا اندرونی Google Sheets کنیکٹر نہیں۔ ای میل نہیں بھیجتا۔ رضامندی کا ثبوت اور اسکرپٹ کا چلنا آپ کی ذمہ داری ہے۔

Sheet اور لسٹ تیار کریں

Contacts ٹیب میں یہی ہیڈرز بنائیں۔ consent کے لیے چیک باکس رکھیں اور مطلوبہ مارکیٹنگ کی اجازت پر ہی TRUE کریں۔

emailfirstNamelastNameconsent
[email protected]JaneDoeTRUE
[email protected]AlexLeeFALSE

Brevo لسٹ بنائیں یا منتخب کریں اور اس کا عددی ID LIST_ID میں دیں۔ Brevo میں FNAME اور LNAME ایٹریبیوٹس موجود ہوں؛ صرف یہی ملائے جاتے ہیں۔ اگر Sheet یہ ثابت نہیں کرتا کہ رضامندی کب اور کیسے ملی تو اصل ریکارڈ الگ رکھیں۔ TRUE سیل بذات خود ثبوت نہیں۔

Extensions → Apps Script → Project Settings → Script Properties میں BREVO_API_KEY شامل کریں۔ پروپرٹیز اسکرپٹ صارفین میں مشترک ہیں، اس لیے ترمیم کی اجازت محدود کریں۔ کی کو سیل یا کوڈ میں نہ رکھیں۔ Google کے رسائی اصول دیکھیں۔

اسکرپٹ

Code.gs کو اس مثال سے بدلیں اور پہلی بار سے پہلے LIST_ID مقرر کریں۔

const LIST_ID = 42; // Replace with your existing Brevo list ID.
const TAB = 'Contacts';
const BASE = 'https://api.brevo.com/v3';
function syncSheetToBrevo() {
const key = PropertiesService.getScriptProperties().getProperty('BREVO_API_KEY');
if (!key) throw new Error('Set BREVO_API_KEY in Script Properties first');
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TAB);
if (!sheet) throw new Error('Contacts tab missing');
const values = sheet.getDataRange().getValues();
const headers = values.shift().map(h => String(h).trim());
const columns = ['email', 'firstName', 'lastName', 'consent']
.map(name => headers.indexOf(name));
if (columns.includes(-1)) throw new Error('Required header missing');
const [emailCol, firstCol, lastCol, consentCol] = columns;
const seen = new Set();
const result = { written: 0, skipped: 0 };
for (const row of values) {
const email = String(row[emailCol] || '').trim().toLowerCase();
if (row[consentCol] !== true || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || seen.has(email)) {
result.skipped++;
continue;
}
seen.add(email);
const path = '/contacts/' + encodeURIComponent(email);
const current = brevo_(key, path, 'get');
if (current.code !== 200 && current.code !== 404) {
throw new Error(`Contact read failed (${current.code}) for row ${result.written + result.skipped + 2}`);
}
if (current.code === 200) {
const contact = JSON.parse(current.text);
if (contact.emailBlacklisted || (contact.listUnsubscribed || []).includes(LIST_ID)) {
result.skipped++;
continue;
}
}
const attributes = {};
if (row[firstCol] !== '') attributes.FNAME = String(row[firstCol]);
if (row[lastCol] !== '') attributes.LNAME = String(row[lastCol]);
const body = { attributes, listIds: [LIST_ID] };
const saved = current.code === 404
? brevo_(key, '/contacts', 'post', { email, ...body })
: brevo_(key, path, 'put', body);
if (![201, 204].includes(saved.code)) {
throw new Error(`Contact write failed (${saved.code}) for ${email}: ${saved.text.slice(0, 200)}`);
}
result.written++;
}
Logger.log(JSON.stringify(result));
return result;
}
function brevo_(key, path, method, body) {
for (let attempt = 0; attempt < 3; attempt++) {
const response = UrlFetchApp.fetch(BASE + path, {
method,
contentType: 'application/json',
headers: { 'api-key': key },
payload: body ? JSON.stringify(body) : undefined,
muteHttpExceptions: true,
});
const code = response.getResponseCode();
if (code !== 429) return { code, text: response.getContentText() };
if (attempt === 2) return { code, text: response.getContentText() };
const reset = Object.entries(response.getHeaders()).find(
([name]) => name.toLowerCase() === 'x-sib-ratelimit-reset'
);
const raw = Number(reset && reset[1]);
const seconds = Number.isFinite(raw) && raw > 0 ? raw : 2 ** attempt;
const waitSeconds = seconds + 2 ** attempt;
if (waitSeconds > 60) return { code, text: response.getContentText() };
Utilities.sleep(waitSeconds * 1000);
}
}

محفوظ کریں، syncSheetToBrevo منتخب کرکے Run دبائیں۔ Google، Sheets اور بیرونی درخواستوں کی اجازت مانگے گا۔ Executions میں {written, skipped} لاگ دیکھیں۔ پڑھنے پر 404 آئے تو کانٹیکٹ بنتا ہے، 200 پر اپ ڈیٹ؛ دوسری خرابی رن روک دیتی ہے۔ کامیاب کانٹیکٹ رائٹ کا مطلب مہم بھیجنا نہیں۔

ایک رن میں اسکرپٹ دوہرے ای میل ہٹاتا ہے اور اگلے رن میں Brevo دوبارہ دیکھتا ہے۔ emailBlacklisted کو false نہیں کرتا اور پتہ نہیں بدلتا۔ Brevo عام بلاک یا ہدف لسٹ سے ان سبسکرائب بتائے تو Sheet میں TRUE کے باوجود قطار چھوڑ دیتا ہے۔ ان سبسکرائب کو پلٹنے کے لیے نہ چلائیں۔ Brevo خبردار کرتا ہے کہ بلاک کانٹیکٹ کا ای میل بدلنے سے بلاک ہٹ سکتا ہے۔

شیڈول سے پہلے ایک رن چیک کریں

اپنی ٹیسٹ لسٹ اور کانٹیکٹ استعمال کریں۔ ایک TRUE، ایک FALSE اور ایک دوہرے ای میل سے ایک رائٹ اور دو اسکیپ متوقع ہیں۔ ٹیسٹ کانٹیکٹ کو Brevo میں ان سبسکرائب کرکے پھر چلائیں: اس کے لیے رائٹ نہیں ہونی چاہیے۔ خرابی جانچنے کو عارضی غلط LIST_ID دیں، Executions میں HTTP خرابی دیکھیں، ID واپس رکھیں اور دہرائیں۔ حقیقی گاہک ڈیٹا پر ٹیسٹ نہ کریں۔ کوڈ کو فرضی Brevo جوابات سے مقامی طور پر جانچا گیا، کوئی لائیو رائٹ نہیں ہوئی۔

Apps Script → Triggers → Add Trigger میں syncSheetToBrevo اور وقت منتخب کریں۔ ٹرگر بنانے والے اکاؤنٹ سے چلتا ہے، جس کی Sheet تک رسائی برقرار رہنی چاہیے۔ چھوٹے Sheet پر روز ایک بار سے شروع کریں اور خرابی دیکھیں۔ Google رن وقت اور URL Fetch استعمال محدود کرتا ہے، بڑے سورس کو محدود کاموں میں بانٹیں۔

429 پر اسکرپٹ x-sib-ratelimit-reset پڑھ کر زیادہ سے زیادہ دو بار دوبارہ کوشش کرتا ہے۔ انتظار 60 سیکنڈ سے زیادہ ہو تو جلدی کوشش کرنے کے بجائے 429 واپس کرتا ہے تاکہ اگلے رن میں کام ہو۔ دوسری خرابی بھی رن روکتی ہے؛ اگلا رن شروع سے چلتا ہے۔ پڑھنے اور لکھنے کے درمیان کانٹیکٹ ان سبسکرائب ہو سکتا ہے۔ یہ مختصر وقفہ قابل قبول ہو تبھی مثال استعمال کریں۔ سخت حفاظت کے لیے ایونٹ ملانا، معتبر رضامندی ریکارڈ اور بھیجنے سے پہلے آخری جانچ چاہیے۔

بڑے Sheet کے لیے Brevo کا غیر ہم وقت امپورٹ processId دیتا ہے۔ اس سے کام قبول ہونا ثابت ہوتا ہے، مکمل ہونا نہیں۔ نتیجہ چیک کریں۔ یہاں ہر کانٹیکٹ کا طریقہ خرابی والی قطار دکھاتا ہے۔

اکثر پوچھے گئے سوالات

کیا Google Sheets کا اندرونی کنیکٹر چاہیے؟

نہیں۔ مثال Sheet سے جڑے Apps Script پروجیکٹ میں چلتی ہے اور Brevo کانٹیکٹ API کال کرتی ہے۔ اسکرپٹ، API کی اور مقررہ ٹرگر آپ سنبھالتے ہیں۔

کون سی قطاریں Brevo جاتی ہیں؟

صرف consent میں TRUE اور درست ای میل والی۔ اسکرپٹ ہر رن میں ڈپلیکیٹ ہٹاتا اور لکھنے سے پہلے Brevo چیک کرتا ہے۔

دوبارہ چلانے سے ان سبسکرائب شخص پھر شامل ہوگا؟

اسکرپٹ Brevo میں emailBlacklisted یا ہدف لسٹ سے ان سبسکرائب کانٹیکٹ چھوڑ دیتا ہے۔ emailBlacklisted: false نہیں بھیجتا، ای میل نہیں بدلتا۔ پروڈکشن سے پہلے رضامندی اور بلاک کے دوسرے ذرائع بھی دیکھیں۔

ناکام رن کیسے دہرائیں؟

Apps Script Executions میں خرابی پڑھیں، وجہ درست کریں اور وہی فنکشن دوبارہ چلائیں۔ ایک ہی ای میل اور لسٹ ID سے پہلے کامیاب قطار دوسرا کانٹیکٹ نہیں بناتی۔

ابتدائی رسائی کی درخواست کریں

اپنا پہلا نام اور دفتری ای میل پتہ درج کریں۔ ہم Tajo تک رسائی کی درخواست کی تصدیق کے لیے ایک لنک ای میل کریں گے۔

Brevo حاصل کریں