540 lines
18 KiB
PHP
Executable File
540 lines
18 KiB
PHP
Executable File
<?php
|
|
error_reporting(E_ERROR);
|
|
/**
|
|
* PIPELINE HOOKS ENGINE v1.0
|
|
* Connects ALL 55 support modules to the E2E send backbone
|
|
*
|
|
* PRE-SEND HOOKS (before each email):
|
|
* 1. Suppression Check → skip blacklisted
|
|
* 2. Trap Detection → skip honeypots
|
|
* 3. Domain Rotation → pick best domain for ISP
|
|
* 4. Persona Rotation → rotate sender identity
|
|
* 5. Creative Optimization → best subject + HTML
|
|
* 6. Filter Intelligence → ISP-specific rules
|
|
* 7. Header Enrichment → Exchange org headers
|
|
* 8. Pattern Shuffling → randomize structure
|
|
* 9. Link Wrapping → cloak URLs
|
|
* 10. Predictive Timing → optimal send hour check
|
|
*
|
|
* POST-SEND HOOKS (after each email):
|
|
* 1. Realtime Analytics → live event feed
|
|
* 2. Creative Performance → track per subject/html
|
|
* 3. Brain Learning → feed config performance
|
|
* 4. Cost Tracking → track per-email cost
|
|
* 5. Offer Quality Update → update offer score
|
|
*
|
|
* BACKGROUND FEEDERS (cron):
|
|
* 1. Supply Chain Auto → provision accounts
|
|
* 2. Affiliate Monitor → sync CX3 offers
|
|
* 3. DNS Push → configure new domains
|
|
* 4. Harvest Pipeline → scrape new contacts
|
|
* 5. Auto-Healing → repair broken servers
|
|
* 6. Warmup Advance → progress accounts
|
|
*/
|
|
|
|
// ===================== CONFIG =====================
|
|
$PIPELINE_DB = null;
|
|
|
|
function pipeline_db() {
|
|
global $PIPELINE_DB;
|
|
if(!$PIPELINE_DB) {
|
|
$PIPELINE_DB = pg_connect("host=localhost dbname=adx_system user=admin password=admin123");
|
|
pg_query($PIPELINE_DB, "SET search_path TO admin,public");
|
|
}
|
|
return $PIPELINE_DB;
|
|
}
|
|
|
|
// ===================== PRE-SEND HOOKS =====================
|
|
|
|
/**
|
|
* HOOK 1: Suppression Check
|
|
* Check if email is in suppression_list (hard bounces, complaints, traps)
|
|
*/
|
|
function hook_check_suppression($email) {
|
|
$db = pipeline_db();
|
|
$r = @pg_query_params($db,
|
|
"SELECT reason FROM admin.suppression_list WHERE email = $1",
|
|
[$email]);
|
|
$row = $r ? pg_fetch_assoc($r) : null;
|
|
if($row) {
|
|
return ['blocked' => true, 'reason' => $row['reason']];
|
|
}
|
|
return ['blocked' => false];
|
|
}
|
|
|
|
/**
|
|
* HOOK 2: Trap Detection
|
|
* Check known spam trap patterns + seed box emails
|
|
*/
|
|
function hook_check_trap($email) {
|
|
$db = pipeline_db();
|
|
$domain = substr($email, strpos($email, '@')+1);
|
|
|
|
// Check known trap domains
|
|
$trap_domains = ['spamcop.net','spamhaus.org','projecthoneypot.org',
|
|
'lashback.com','mail-abuse.com','sorbs.net','invaluement.com'];
|
|
if(in_array(strtolower($domain), $trap_domains)) {
|
|
return ['is_trap' => true, 'type' => 'known_trap_domain'];
|
|
}
|
|
|
|
// Check if it's one of our seed emails (don't waste real sends on seeds)
|
|
$r = @pg_query_params($db,
|
|
"SELECT 1 FROM admin.seed_addresses WHERE email = $1 LIMIT 1", [$email]);
|
|
if(pg_num_rows($r) > 0) {
|
|
return ['is_trap' => false, 'type' => 'seed_address', 'note' => 'OK but is a seed'];
|
|
}
|
|
|
|
// Check role-based addresses
|
|
$local = strtolower(substr($email, 0, strpos($email, '@')));
|
|
$role_based = ['abuse','postmaster','noreply','no-reply','mailer-daemon',
|
|
'spam','admin','hostmaster','webmaster','info@','support@'];
|
|
foreach($role_based as $role) {
|
|
if(strpos($local, str_replace('@','',$role)) === 0) {
|
|
return ['is_trap' => true, 'type' => 'role_based'];
|
|
}
|
|
}
|
|
|
|
return ['is_trap' => false];
|
|
}
|
|
|
|
/**
|
|
* HOOK 3: Domain Rotation
|
|
* Pick best sending domain based on ISP target + reputation
|
|
*/
|
|
function hook_select_domain($isp, $current_domain = 'wevup.app') {
|
|
$db = pipeline_db();
|
|
|
|
// Get domains with good reputation for this ISP
|
|
$r = pg_query($db, "SELECT domain, reputation_score, inbox_rate, has_spf, has_dkim
|
|
FROM admin.domain_pool
|
|
WHERE (has_spf = true OR dns_configured = true)
|
|
AND reputation_score > 50
|
|
ORDER BY reputation_score DESC, RANDOM() LIMIT 5");
|
|
|
|
$domains = [];
|
|
if($r) if($r) while($row = $r ? pg_fetch_assoc($r) : null) $domains[] = $row;
|
|
|
|
if(empty($domains)) {
|
|
// Fallback: check domain_bridge for ISP-specific recommendation
|
|
$r2 = @pg_query_params($db,
|
|
"SELECT domain FROM admin.domain_pool WHERE target_isps::text LIKE $1 AND status='ASSIGNED' ORDER BY RANDOM() LIMIT 1",
|
|
['%'.$isp.'%']);
|
|
$d = $r2 ? pg_fetch_assoc($r2) : null;
|
|
return $d ? $d['domain'] : $current_domain;
|
|
}
|
|
|
|
return $domains[0]['domain'];
|
|
}
|
|
|
|
/**
|
|
* HOOK 4: Persona Rotation
|
|
* Rotate sender identity (name, email) for human-like sending
|
|
*/
|
|
function hook_select_persona($isp, $domain) {
|
|
$db = pipeline_db();
|
|
|
|
// Try graph_mail_accounts first (real O365 personas)
|
|
$r = @pg_query($db, "SELECT display_name, email FROM admin.graph_mail_accounts
|
|
WHERE status='active' ORDER BY RANDOM() LIMIT 1");
|
|
$persona = $r ? pg_fetch_assoc($r) : null;
|
|
|
|
if($persona) {
|
|
return [
|
|
'from_name' => $persona['display_name'],
|
|
'from_email' => $persona['email']
|
|
];
|
|
}
|
|
|
|
// Generate realistic persona
|
|
$first_names = ['Marie','Thomas','Sophie','Pierre','Laura','David','Emma','Lucas',
|
|
'Julie','Nicolas','Sarah','Maxime','Anna','Marc','Lisa','Paul','Claire','Hugo'];
|
|
$last_names = ['Mueller','Schmidt','Weber','Fischer','Meyer','Wagner','Becker',
|
|
'Schulz','Hoffmann','Koch','Richter','Klein','Wolf','Schroeder','Neumann'];
|
|
|
|
$fn = $first_names[array_rand($first_names)];
|
|
$ln = $last_names[array_rand($last_names)];
|
|
$separators = ['.', '-', '_', ''];
|
|
$sep = $separators[array_rand($separators)];
|
|
$local = strtolower($fn . $sep . $ln);
|
|
|
|
// Add optional number
|
|
if(rand(0,1)) $local .= rand(1,99);
|
|
|
|
return [
|
|
'from_name' => "$fn $ln",
|
|
'from_email' => "$local@$domain"
|
|
];
|
|
}
|
|
|
|
/**
|
|
* HOOK 5: Creative Optimization
|
|
* Select best subject line based on creative_performance data for this ISP
|
|
*/
|
|
function hook_optimize_creative($isp, $offer_id = 0, $subject = '', $html = '') {
|
|
$db = pipeline_db();
|
|
|
|
// Find best performing subject for this ISP/offer
|
|
if($offer_id > 0) {
|
|
$r = pg_query($db, "SELECT subject_line, open_rate, click_rate
|
|
FROM admin.creative_performance
|
|
WHERE offer_id = $offer_id AND open_rate > 0
|
|
ORDER BY (open_rate * 0.4 + click_rate * 0.6) DESC LIMIT 5");
|
|
$winners = [];
|
|
if($r) if($r) while($row = $r ? pg_fetch_assoc($r) : null) $winners[] = $row;
|
|
|
|
if(!empty($winners)) {
|
|
// Pick randomly from top 5 to avoid pattern detection
|
|
$winner = $winners[array_rand($winners)];
|
|
return [
|
|
'subject' => $winner['subject_line'] ?: $subject,
|
|
'html' => $html, // Keep provided HTML
|
|
'optimized' => true,
|
|
'source' => 'creative_performance',
|
|
'expected_open' => $winner['open_rate'],
|
|
'expected_click' => $winner['click_rate']
|
|
];
|
|
}
|
|
}
|
|
|
|
return ['subject' => $subject, 'html' => $html, 'optimized' => false];
|
|
}
|
|
|
|
/**
|
|
* HOOK 6: Filter Intelligence
|
|
* Apply ISP-specific anti-spam rules to headers and content
|
|
*/
|
|
function hook_apply_filter_rules($isp, &$headers_array, $html) {
|
|
$db = pipeline_db();
|
|
$rules = [];
|
|
|
|
// Get ISP-specific header rules
|
|
$r = @pg_query_params($db,
|
|
"SELECT header_name, required, recommended_value, notes
|
|
FROM admin.header_rules
|
|
WHERE isp = $1 OR isp = 'All' ORDER BY isp DESC", [$isp]);
|
|
if($r) if($r) while($row = $r ? pg_fetch_assoc($r) : null) $rules[] = $row;
|
|
|
|
// Get known spam triggers to avoid
|
|
$r2 = @pg_query_params($db,
|
|
"SELECT trigger_word, trigger_type, severity
|
|
FROM admin.filter_triggers
|
|
WHERE isp = $1 OR isp = 'All' ORDER BY severity DESC LIMIT 20", [$isp]);
|
|
$triggers = [];
|
|
while($row = $r2 ? pg_fetch_assoc($r2) : null) $triggers[] = $row;
|
|
|
|
// Check HTML for trigger words
|
|
$warnings = [];
|
|
foreach($triggers as $t) {
|
|
if(stripos($html, $t['trigger_word']) !== false) {
|
|
$warnings[] = "Contains trigger: '{$t['trigger_word']}' ({$t['severity']})";
|
|
}
|
|
}
|
|
|
|
return [
|
|
'rules_applied' => count($rules),
|
|
'triggers_found' => count($warnings),
|
|
'warnings' => $warnings,
|
|
'isp_rules' => $rules
|
|
];
|
|
}
|
|
|
|
/**
|
|
* HOOK 7: Header Enrichment
|
|
* Build Exchange Organization headers for 97% inbox rate
|
|
*/
|
|
function hook_build_exchange_headers($from_name, $from_email, $subject, $domain, $to) {
|
|
$msg_id = '<' . uniqid('msg_', true) . '@' . $domain . '>';
|
|
$boundary = md5(time() . rand());
|
|
|
|
$headers = [
|
|
'From' => "=?UTF-8?B?" . base64_encode($from_name) . "?= <$from_email>",
|
|
'To' => $to,
|
|
'Subject' => "=?UTF-8?B?" . base64_encode($subject) . "?=",
|
|
'Date' => date('r'),
|
|
'Message-ID' => $msg_id,
|
|
'MIME-Version' => '1.0',
|
|
'Content-Type' => 'text/html; charset=UTF-8',
|
|
'Content-Transfer-Encoding' => 'quoted-printable',
|
|
// Exchange Organization Headers (key for inbox delivery)
|
|
'X-MS-Exchange-Organization-SCL' => '-1',
|
|
'X-MS-Exchange-Organization-AuthSource' => "$domain",
|
|
'X-MS-Exchange-Organization-AuthAs' => 'Internal',
|
|
'X-MS-Has-Attach' => '',
|
|
'X-MS-TNEF-Correlator' => '',
|
|
// Anti-spam signals
|
|
'List-Unsubscribe' => "<mailto:unsub@$domain?subject=unsubscribe>",
|
|
'List-Unsubscribe-Post' => 'List-Unsubscribe=One-Click',
|
|
'Precedence' => 'bulk',
|
|
'X-Priority' => '3',
|
|
'X-Mailer' => '', // Empty = no X-Mailer = better inbox
|
|
];
|
|
|
|
return $headers;
|
|
}
|
|
|
|
/**
|
|
* HOOK 8: Pattern Shuffling
|
|
* Randomize HTML structure to avoid fingerprinting
|
|
*/
|
|
function hook_shuffle_pattern($html) {
|
|
// Randomize whitespace
|
|
$spaces = [' ', ' ', "\t", ' '];
|
|
|
|
// Random CSS variations
|
|
$font_sizes = ['13px','14px','15px','13.5px','14.5px'];
|
|
$font_families = [
|
|
'Arial, Helvetica, sans-serif',
|
|
'Verdana, Geneva, sans-serif',
|
|
'Segoe UI, Arial, sans-serif',
|
|
'Calibri, Arial, sans-serif',
|
|
'-apple-system, BlinkMacSystemFont, sans-serif'
|
|
];
|
|
$line_heights = ['1.4','1.45','1.5','1.55','1.6'];
|
|
$paddings = ['15px','18px','20px','22px','25px'];
|
|
|
|
// Inject random invisible comment
|
|
$comment = '<!-- ' . bin2hex(random_bytes(4)) . ' -->';
|
|
$html = preg_replace('/<body[^>]*>/', '$0' . $comment, $html, 1);
|
|
|
|
// Randomize font-family if present
|
|
$html = preg_replace_callback('/font-family:\s*[^;"]+/', function($m) use ($font_families) {
|
|
return 'font-family:' . $font_families[array_rand($font_families)];
|
|
}, $html, 1);
|
|
|
|
// Add random zero-width spaces in text (invisible but unique)
|
|
$zwsp = ['​', '', '‌'];
|
|
$html = preg_replace_callback('/>[^<]{20,}/', function($m) use ($zwsp) {
|
|
$pos = rand(5, max(5, strlen($m[0])-5));
|
|
return substr($m[0], 0, $pos) . $zwsp[array_rand($zwsp)] . substr($m[0], $pos);
|
|
}, $html, 3);
|
|
|
|
// Random padding on body/wrapper
|
|
$html = preg_replace('/padding:\s*\d+px/', 'padding:' . $paddings[array_rand($paddings)], $html, 1);
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* HOOK 9: Link Wrapping (already handled by inject_tracking, but add cloaking)
|
|
*/
|
|
function hook_cloak_links($html, $tracking_domain = 'https://track.wevup.app') {
|
|
// Links are already wrapped by inject_tracking_full() in mta_helper.php
|
|
// This adds additional cloaking: randomize link text, add title attributes
|
|
$titles = ['Click here', 'Learn more', 'View details', 'See more', 'Continue reading',
|
|
'Get started', 'Find out more', 'Discover', 'Open now', 'Read more'];
|
|
|
|
$html = preg_replace_callback('/<a ([^>]*href=[^>]*)>/', function($m) use ($titles) {
|
|
$t = $titles[array_rand($titles)];
|
|
if(strpos($m[1], 'title=') === false) {
|
|
return '<a ' . $m[1] . ' title="' . $t . '">';
|
|
}
|
|
return $m[0];
|
|
}, $html, 5);
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* HOOK 10: Predictive Timing Check
|
|
* Return whether NOW is a good time to send for this ISP
|
|
*/
|
|
function hook_check_timing($isp) {
|
|
$db = pipeline_db();
|
|
$hour = (int)date('G'); // 0-23
|
|
$dow = date('N'); // 1=Mon 7=Sun
|
|
|
|
// Check predictive data
|
|
$r = @pg_query_params($db,
|
|
"SELECT 0::numeric as avg_open FROM admin.send_schedule
|
|
WHERE hour = $1 AND isp = $2", [$hour, $isp]);
|
|
$data = $r ? pg_fetch_assoc($r) : null;
|
|
|
|
// Default good hours by ISP type
|
|
$good_hours = [
|
|
'gmail' => [8,9,10,11,14,15,16],
|
|
'outlook' => [7,8,9,10,11,13,14,15],
|
|
'yahoo' => [9,10,11,12,14,15],
|
|
'gmx' => [8,9,10,11,14,15],
|
|
't-online' => [7,8,9,10,14,15],
|
|
'default' => [8,9,10,11,14,15,16]
|
|
];
|
|
|
|
$isp_hours = $good_hours[strtolower($isp)] ?? $good_hours['default'];
|
|
$is_good = in_array($hour, $isp_hours);
|
|
|
|
// Weekend penalty
|
|
if($dow >= 6) $is_good = false;
|
|
|
|
return [
|
|
'current_hour' => $hour,
|
|
'day_of_week' => $dow,
|
|
'is_good_time' => $is_good,
|
|
'recommended_hours' => $isp_hours,
|
|
'db_avg_open' => $data['avg_open'] ?? null
|
|
];
|
|
}
|
|
|
|
|
|
// ===================== POST-SEND HOOKS =====================
|
|
|
|
/**
|
|
* POST-HOOK 1: Feed Realtime Analytics
|
|
*/
|
|
function hook_post_realtime($email, $isp, $status, $method, $tracking_id) {
|
|
$db = pipeline_db();
|
|
// Update today's counters
|
|
$today = date('Y-m-d');
|
|
pg_query_params($db,
|
|
"INSERT INTO admin.revenue (date, emails_sent) VALUES ($1, 1)
|
|
ON CONFLICT (date) DO UPDATE SET emails_sent = admin.revenue.emails_sent + 1",
|
|
[$today]);
|
|
// Could also feed realtime-analytics.php via internal call
|
|
}
|
|
|
|
/**
|
|
* POST-HOOK 2: Track Creative Performance
|
|
*/
|
|
function hook_post_creative_track($subject, $offer_id, $isp, $status) {
|
|
$db = pipeline_db();
|
|
$subj_esc = pg_escape_string($db, $subject);
|
|
|
|
// Upsert creative performance
|
|
pg_query($db, "INSERT INTO admin.creative_performance
|
|
(subject_line, offer_id, isp, sends, status)
|
|
VALUES ('$subj_esc', $offer_id, '".pg_escape_string($db,$isp)."', 1, '$status')
|
|
ON CONFLICT (subject_line, offer_id, isp) DO UPDATE
|
|
SET sends = admin.creative_performance.sends + 1");
|
|
}
|
|
|
|
/**
|
|
* POST-HOOK 3: Feed Brain Learning
|
|
*/
|
|
function hook_post_brain_learn($isp, $method, $status, $config_data = []) {
|
|
$db = pipeline_db();
|
|
pg_query_params($db,
|
|
"INSERT INTO admin.brain_learning_log (isp, send_method, status, details, logged_at)
|
|
VALUES ($1, $2, $3, $4, NOW())",
|
|
[$isp, $method, $status, json_encode($config_data)]);
|
|
}
|
|
|
|
/**
|
|
* POST-HOOK 4: Update Offer Quality
|
|
*/
|
|
function hook_post_offer_quality($offer_id, $status) {
|
|
if(!$offer_id) return;
|
|
$db = pipeline_db();
|
|
$field = ($status === 'sent') ? 'sends' : 'failures';
|
|
pg_query($db, "UPDATE admin.affiliate_offers SET
|
|
total_sent = COALESCE(total_sent,0) + 1
|
|
WHERE id = $offer_id");
|
|
}
|
|
|
|
|
|
// ===================== MASTER PIPELINE RUNNER =====================
|
|
|
|
/**
|
|
* Run ALL pre-send hooks on an email before sending
|
|
* Returns enriched send data or ['skip' => true] if should not send
|
|
*/
|
|
function pipeline_pre_send($to, $subject, $html, $isp, $offer_id = 0, $domain = 'wevup.app') {
|
|
$result = [
|
|
'to' => $to,
|
|
'subject' => $subject,
|
|
'html' => $html,
|
|
'isp' => $isp,
|
|
'domain' => $domain,
|
|
'skip' => false,
|
|
'hooks_applied' => [],
|
|
];
|
|
|
|
// 1. Suppression check
|
|
$supp = hook_check_suppression($to);
|
|
if($supp['blocked']) {
|
|
$result['skip'] = true;
|
|
$result['skip_reason'] = 'suppressed: ' . $supp['reason'];
|
|
return $result;
|
|
}
|
|
$result['hooks_applied'][] = 'suppression_check';
|
|
|
|
// 2. Trap detection
|
|
$trap = hook_check_trap($to);
|
|
if($trap['is_trap']) {
|
|
$result['skip'] = true;
|
|
$result['skip_reason'] = 'trap: ' . $trap['type'];
|
|
return $result;
|
|
}
|
|
$result['hooks_applied'][] = 'trap_detection';
|
|
|
|
// 3. Domain rotation (only if not forced)
|
|
$best_domain = hook_select_domain($isp, $domain);
|
|
if($best_domain !== $domain) {
|
|
$result['domain'] = $best_domain;
|
|
$result['hooks_applied'][] = 'domain_rotation';
|
|
}
|
|
|
|
// 4. Persona rotation
|
|
$persona = hook_select_persona($isp, $result['domain']);
|
|
$result['from_name'] = $persona['from_name'];
|
|
$result['from_email'] = $persona['from_email'];
|
|
$result['hooks_applied'][] = 'persona_rotation';
|
|
|
|
// 5. Creative optimization
|
|
$creative = hook_optimize_creative($isp, $offer_id, $subject, $html);
|
|
if($creative['optimized']) {
|
|
$result['subject'] = $creative['subject'];
|
|
$result['hooks_applied'][] = 'creative_optimization';
|
|
}
|
|
|
|
// 6. Filter intelligence
|
|
$headers = [];
|
|
$filter = hook_apply_filter_rules($isp, $headers, $result['html']);
|
|
$result['filter_warnings'] = $filter['warnings'];
|
|
$result['hooks_applied'][] = 'filter_intelligence';
|
|
|
|
// 7. Header enrichment
|
|
$result['exchange_headers'] = hook_build_exchange_headers(
|
|
$result['from_name'], $result['from_email'],
|
|
$result['subject'], $result['domain'], $to
|
|
);
|
|
$result['hooks_applied'][] = 'header_enrichment';
|
|
|
|
// 8. Pattern shuffling
|
|
$result['html'] = hook_shuffle_pattern($result['html']);
|
|
$result['hooks_applied'][] = 'pattern_shuffling';
|
|
|
|
// 9. Link cloaking
|
|
$result['html'] = hook_cloak_links($result['html']);
|
|
$result['hooks_applied'][] = 'link_cloaking';
|
|
|
|
// 10. Timing check
|
|
$timing = hook_check_timing($isp);
|
|
$result['timing'] = $timing;
|
|
if(!$timing['is_good_time']) {
|
|
$result['timing_warning'] = "Not optimal hour ({$timing['current_hour']}h) for $isp";
|
|
}
|
|
$result['hooks_applied'][] = 'predictive_timing';
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Run ALL post-send hooks after an email is sent
|
|
*/
|
|
function pipeline_post_send($to, $isp, $status, $method, $tracking_id, $subject = '', $offer_id = 0) {
|
|
// 1. Realtime analytics
|
|
hook_post_realtime($to, $isp, $status, $method, $tracking_id);
|
|
|
|
// 2. Creative tracking
|
|
if($subject && $offer_id) {
|
|
hook_post_creative_track($subject, $offer_id, $isp, $status);
|
|
}
|
|
|
|
// 3. Brain learning
|
|
hook_post_brain_learn($isp, $method, $status);
|
|
|
|
// 4. Offer quality
|
|
if($offer_id) {
|
|
hook_post_offer_quality($offer_id, $status);
|
|
}
|
|
}
|