Egy projekt kapcsán feldobták a feladatot: Mikor egy ügyfél felad egy hirdetést, a nyomonkövethetőség okán generáljon hozzá a rendszer egy e-mail címet, és azt jelenítse meg a usernek, majd erre az e-mail címre érkező, majd továbbított levelek száma legyen nyilvántartva, hogy fel tudjunk mutatni egy statisztikát, mennyire volt az sikeres.
Ennek megoldásához a már eleve MySQL alapokon működő eximünket módosítottam úgy, hogy a szükséges címek leválogatását rábízza egy UDF-re, egy egyszerű select eredményeképpen megkapjuk a listát, és maga a MySQL intézze el a továbbítások számolását.
Az exim MySQL-re átpattintásába most nem mennék bele, az egy bővebb téma lenne. Erre ajánlom Pásztor János kolléga által igen részletesen megírt "A nagy Exim tutorial" című cikket.
A levelek automatikus továbbításához létrehozunk egy táblát:
Úgy gondolom, a mezők tartalma a nevük alapján nyilvánvaló.
Egy sima auto-forward exim szinten így néz ki:
Ennek magyarázását most kihagyom, mivel most nem ez a poszt témája. Ettől függetlenül, ha csak sima auto-forward érdekel, ezt nyugodtan használhatod :) Ehhez egyébként nem szükséges lokálisan kezelt postafiók, csak az adott domain MX rekordja legyen a miénk.
Röviden amit a fenti tud:
Ezen is változtatunk egy kicsit, így a következőt fogja tudni az eximünk:
Exim-nek fontos, hogy a data értéke az új címek listája legyen, minden cím új sorban, minden sallang nélkül.
Ezt a feltételt lovagoljuk meg, és csinálunk egy tárolt eljárást, ami leválogatja az új címeket, a továbbítások számát növeli eggyel, és visszatér az exim-hez.
Ehhez először kiegészítjük az exim_forward táblánkat egy fw_count, egy last_exim_id mezővel és az elsődleges kulcsot módosítjuk egy sima auto_increment mezőre:
A last_exim_id-t eredetileg azért találtam ki, mert a továbbítások számolása során adódott egy kis probléma, miszerint az exim kétszer lookup-ol egy e-mail címre. Bevallom, mélyrehatóan nem néztem utána, de ha jól vettem ki, ennek az az oka, hogy első ízben ellenőrzi van-e mivel foglalkozni (van hova redirect-elni?), majd a tényleges továbbításhoz ismét lekéri a címlistát.
Szóval ennek köszönhetően a fw_count mező értéke mindig duplázódott, ami ugyan kikerülhető egy sima felezéssel, de nem valami elegáns. Első nekifutásra úgy gondoltam, hogy minden lookup alkalmával megkapom az e-mail exim által generált azonosítóját, ami egyrészről biztos egyedi, másrészről tudok ellenőrizni, ha az adott e-mailhez tartozó előző exim_id megegyezik az aktuálissal, akkor nem növelem az fw_count értékét.
Ez az elképzelés hibásnak bizonyult, tekintve, hogy első alkalommal még nem generál azonosítót az exim, akkor még a megkapott exim_id érték üres. Magán a megoldáson nem túl sokat módosít ez a tény, hiszen ez is könnyen ellenőrizhető, illetőleg a last_exim_id legalább egy plusz információ lehet, ha bármi okból utána kell néznünk mondjuk az utolsó forwardnak.
Az előző tárolteljárásosfüggvényestriggeres írásomhoz képest nem túl sok dologgal fog többet mutatni a most használt függvény. Használni fogunk változókat, kurzort, iterálni fogunk eredményhalmazon, illetve alap MySQL függvényeket fogunk használni.
Lássuk magát az ördögöt:
Az UDF-ek szintaktikája minimálisan különbözik a tárolt eljárásokétól:
A paraméterlista mint látható a fenti kódban "név TIPUS" felsorolás, ahol a típus bármely MySQL adattípus lehet. Ez igaz a visszatérési értékre is (RETURNS TIPUS).
Nekünk jelen esetben szükségünk lesz az eredeti e-mail cím local_part és domain részeire, illetőleg a már korábban említett exim által generált azonosítóra.
Én következetesen használok prefix-eket a változók megkülönböztetésére, így sokkal olvashatóbb és átláthatóbb lesz a kód. Az UDF paramétereit arg, az általam deklarált változókat pedig var prefixekkel látom el.
A characteristic rész a következőket tartalmazhatja:
Ez a rész azonban a MySQL számára csak jelzésértékű információkat tartalmaz, azok hatására a függvény vagy tárolt eljárás futása, eredménye nem változik. Éppen ezért ez a characteristic rész opcionális, akár el is hagyható teljes egészében.
A felsorolt információk szerintem egyértelműek, egyedül a DETERMINISTIC rész lehet idegen, ami csupán annyit árul el, hogy az UDF azonos paraméterek mellett ugyanazt az eredményt fogja-e prezentálni vagy sem.
Rutin törzs...
Először is deklaráljuk a későbbiekben használt változóinkat, kurzorainkat handlereinket.
Amit a kurzorokról tudni kell:
MySQL-ben használhatunk kurzorokat tárolt eljárásokban, függvényekben és triggerekben egyaránt. Segítségükkel egy lekérdezés eredményeként visszatérő eredményhalmazon iterálhatunk végig. A kurzorokkal csak egy irányba haladhatsz, nem hagyhatsz ki sorokat és nem léphetsz visszafelé (Non-scrollable). Nyitott kurzornál ne módosítsd a táblát, különben megbízhatatlan eredményt fogsz kapni (Asensitive).
Kurzorok előtt csak a deklarációs rész állhat, nem SET-elhetünk példának okáért változókat. Ezért is van a fenti kódban az, hogy bár az előzőleg deklarált változókat használjuk a kurzorban, azoknak az értékét csak a kurzor deklaráció után állítjuk be. Ezeknek az értékeknek a feltöltése a kurzorban úgyis csak annak a megnyitása során történik meg.
Kurzorok használatához a következő parancsokat kell ismernünk.
Először is deklarálnunk kell azt:
Következő lépésként meg kell nyitnunk a kurzort az OPEN paranccsal, mielőtt eredményeket szeretnénk lekérdezni:
Lekérdezni a kurzorként deklarált SELECT következő sorát, és tovább lépni az azt követőre a FETCH paranccsal lehet:
A variable list azaz a változólista annyit tesz, hogy a kurzor által deklarált SELECT-ben lekérdezett mezők mely változókat töltsék fel értékkel. Fontos, hogy minden lekérdezett mezőhöz tartoznia kell egy változónak, különben panaszkodni fog a MySQL, hogy nem stimmel a változók száma.
Végül pedig a nyitott kurzort le kell zárni, hogy deaktiválódjon, és felszabadítsuk a memóriát ami az adott kurzorhoz lett lefoglalva.
Az egyik legfontosabb pontja a kurzorok használatának a NOT FOUND handlerek deklarálása, a lekérdezésünk "no data to fetch" eredményének lekezelésére:
Fontos, hogy ezzel nem azt mondtuk, hogy a var_no_more_addresses kezdőértéke 1, hanem azt, ha a FETCH utasítás nem ad vissza eredményt, ezt a változót állítsa 1-re! Ergo magát a változót előbb deklarálnunk kell (ahogy ezt meg is tettük), és vagy inicializáljuk azt, vagy nem.
A mi kurzorunk egy olyan lekérdezés eredményét adja, amiben lekérdezzük a célcímeket konkrét e-mail illetve domain (*@domain) alapján.
A 18. 19. sorokban összeállítottuk magát az eredeti e-mail címet, és a domainhez szükséges joker címet, a későbbi egyszerűbb használat érdekében.
No itt jön a kurzor, amit megnyitunk, majd a soron következő eredményeket a korábban deklarált változókba töltjük, és elkezdünk végig iterálni a sorokon a kurzorunk segítségével.
Mint látható, a WHILE egy elöltesztelős ciklus, aminek nincs hátultesztelős verziója. Ha ilyet szeretnénk, akkor a REPEAT-et kell használnunk:
Az első FETCH utasítás azért a ciklus előtt van kiadva, mivel abba már csak akkor szeretnénk belekezdeni (és addig iterálni) ha (amíg) van eredmény.
A 25-27. sorokban ellenőrizzük a célcímet. Amennyiben az egy joker e-mail, az azt jelenti, hogy az új funkcionalitásról van szó, azaz egy komplett domaint irányítunk át egy másik domainre, megtartva a címzettet. Ebben az esetben a * helyére behelyettesítjük az eredeti postafiók nevet. Így valósul meg a barmi@teszt.hu -> barmi@teszt2.hu
A következő lépéseket csak akkor csináljuk meg, ha az aktuálisan megkapott célcím nem NULL, nem szerepel még az eredménylistában és a hossza nagyobb mint 5 karakter (6 karakteres a@a.hu mint legrövidebb előfordulási lehetőség)
Ha ezeknek a feltételeknek megfelel az e-mail cím amit kaptunk, hozzáfűzzük az eredménylistához újsor karakterrel a végén.
A 31-33. sor tartalmazza egyrészről a forwardolás tényének rögzítését, másrészről pedig a korábban említett ellenőrzést az exim_id alapján. Csak akkor számoljuk el a lekérdezést tényleges továbbításnak, ha van exim_id, és nem egyezik az előző exim_id -vel. Ekkor mondhatjuk csak ugyanis, hogy az exim ténylegesen a címlistára kíváncsi, hogy hova küldje a beérkező levelet (mint korábban említettem, első alkalommal csak megkérdezi, hogy van-e mivel foglalkoznia, akkor még exim_id sincs).
Mindezeket követően még a cikluson belül tovább kell löknünk a kurzort a következő rekordra. Amennyiben ennek not found az eredménye, a not found handlerünk a var_no_more_addresses értékét 1-re állítja, így a ciklusunk a végéhez ért.
A lefutott ciklus után lezárjuk a kurzort, a var_no_more_addresses értékét visszaállítjuk 0-ra, és visszatérünk a leválogatott e-mail címekkel amik külön sorokban szerepelnek, és fel tudja őket dolgozni az exim.
A függvényünk már készen van, be is töltöttük a MySQL-be, de még az eximet meg kell tanítanunk rá, hogy használja is. Ehhez módosítanunk kell a lookup-ot a userforward-ban:
Ugye nem is volt bonyolult :D
Próbáljuk is ki. Először vegyünk fel egy új rekordot az exim_forward táblánkba:
Majd küldjünk egy e-mailt a nullstring@teszt.hu címre, amit a nullstring@teszt2.hu címen szeretnénk ha landolna, és nézzük mit csinál az exim:
Egyértelműen látható, hogy a felado@felado.hu -tól érkező nullstring@teszt.hu címre küldött levél esetén sikeresen lekérdezte az új e-mail címet, és arra tovább is küldte a levelet.
Nade fel is jegyezte ennek a tényét?
Úgy tűnik igen, hiszen az fw_count értéke immáron 1. Az exim által generált azonosító is helyesen lett letárolva, így nincs más hátra mint előre,
ugorjunk bele a szilveszterbe! :D
BUÉK!
Ennek megoldásához a már eleve MySQL alapokon működő eximünket módosítottam úgy, hogy a szükséges címek leválogatását rábízza egy UDF-re, egy egyszerű select eredményeképpen megkapjuk a listát, és maga a MySQL intézze el a továbbítások számolását.
Az exim MySQL-re átpattintásába most nem mennék bele, az egy bővebb téma lenne. Erre ajánlom Pásztor János kolléga által igen részletesen megírt "A nagy Exim tutorial" című cikket.
A levelek automatikus továbbításához létrehozunk egy táblát:
CREATE TABLE IF NOT EXISTS `exim_forward` ( `email` varchar(128) NOT NULL default '', `newaddress` varchar(128) NOT NULL default '', PRIMARY KEY (`email`,`newaddress`), KEY `email_index` (`email`) );
Úgy gondolom, a mezők tartalma a nevük alapján nyilvánvaló.
Egy sima auto-forward exim szinten így néz ki:
userforward: local_parts = !default driver = redirect data = ${lookup mysql{select distinct(newaddress) from exim_forward where email = '${local_part}@${domain}'}{$value}{${lookup mysql{select email from exim_mail where email = '${local_part}@${domain}'}{$value}{${lookup mysql{select distinct(newaddress) from exim_forward where email='*@${domain}'}{$value}fail}}}}} check_ancestor
Ennek magyarázását most kihagyom, mivel most nem ez a poszt témája. Ettől függetlenül, ha csak sima auto-forward érdekel, ezt nyugodtan használhatod :) Ehhez egyébként nem szükséges lokálisan kezelt postafiók, csak az adott domain MX rekordja legyen a miénk.
Röviden amit a fenti tud:
e-mail -> e-mail // teszt@tesz.hu -> teszt2@teszt2.hu
domain (*@domain.tld) -> e-mail // barmi@teszt.hu -> fixcim@teszt2.hu
Ezen is változtatunk egy kicsit, így a következőt fogja tudni az eximünk:
e-mail -> e-mail // teszt@tesz.hu -> teszt2@teszt2.hu
domain (*@domain.tld) -> e-mail // barmi@teszt.hu -> fixcim@teszt2.hu
domain (*@domain.tld) -> domain (*@domain.tld) // barmi@teszt.hu -> barmi@teszt2.hu
Exim-nek fontos, hogy a data értéke az új címek listája legyen, minden cím új sorban, minden sallang nélkül.
Ezt a feltételt lovagoljuk meg, és csinálunk egy tárolt eljárást, ami leválogatja az új címeket, a továbbítások számát növeli eggyel, és visszatér az exim-hez.
Ehhez először kiegészítjük az exim_forward táblánkat egy fw_count, egy last_exim_id mezővel és az elsődleges kulcsot módosítjuk egy sima auto_increment mezőre:
ALTER TABLE `exim_forward` ADD `fw_count` INT NOT NULL DEFAULT '0'; ALTER TABLE `exim_forward` ADD `last_exim_id` VARCHAR( 255 ) NULL; ALTER TABLE `exim_forward` DROP PRIMARY KEY, ADD UNIQUE (`email`, `newaddress`); ALTER TABLE `exim_forward` ADD `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;
A last_exim_id-t eredetileg azért találtam ki, mert a továbbítások számolása során adódott egy kis probléma, miszerint az exim kétszer lookup-ol egy e-mail címre. Bevallom, mélyrehatóan nem néztem utána, de ha jól vettem ki, ennek az az oka, hogy első ízben ellenőrzi van-e mivel foglalkozni (van hova redirect-elni?), majd a tényleges továbbításhoz ismét lekéri a címlistát.
Szóval ennek köszönhetően a fw_count mező értéke mindig duplázódott, ami ugyan kikerülhető egy sima felezéssel, de nem valami elegáns. Első nekifutásra úgy gondoltam, hogy minden lookup alkalmával megkapom az e-mail exim által generált azonosítóját, ami egyrészről biztos egyedi, másrészről tudok ellenőrizni, ha az adott e-mailhez tartozó előző exim_id megegyezik az aktuálissal, akkor nem növelem az fw_count értékét.
Ez az elképzelés hibásnak bizonyult, tekintve, hogy első alkalommal még nem generál azonosítót az exim, akkor még a megkapott exim_id érték üres. Magán a megoldáson nem túl sokat módosít ez a tény, hiszen ez is könnyen ellenőrizhető, illetőleg a last_exim_id legalább egy plusz információ lehet, ha bármi okból utána kell néznünk mondjuk az utolsó forwardnak.
Az előző tárolteljárásosfüggvényestriggeres írásomhoz képest nem túl sok dologgal fog többet mutatni a most használt függvény. Használni fogunk változókat, kurzort, iterálni fogunk eredményhalmazon, illetve alap MySQL függvényeket fogunk használni.
Lássuk magát az ördögöt:
DROP FUNCTION IF EXISTS get_forwardset; DELIMITER // CREATE DEFINER=CURRENT_USER FUNCTION get_forwardset(arg_local_part VARCHAR(64), arg_domain VARCHAR(255), arg_exim_id VARCHAR(255)) RETURNS TEXT NOT DETERMINISTIC MODIFIES SQL DATA BEGIN DECLARE var_orig_email VARCHAR(255); DECLARE var_joker_email VARCHAR(255); DECLARE var_no_more_addresses INT DEFAULT '0'; DECLARE var_curr_id INT; DECLARE var_curr_address VARCHAR(255); DECLARE var_curr_last_exim_id VARCHAR(255); DECLARE result_addresses TEXT DEFAULT ''; DECLARE cur_fw_select CURSOR FOR SELECT DISTINCT newaddress, id, last_exim_id FROM exim_forward WHERE email = var_joker_email OR email = var_orig_email; DECLARE CONTINUE HANDLER FOR NOT FOUND SET var_no_more_addresses = 1; SET var_orig_email = CONCAT(arg_local_part, '@', arg_domain); SET var_joker_email = CONCAT('*@', arg_domain); OPEN cur_fw_select; FETCH cur_fw_select INTO var_curr_address, var_curr_id, var_curr_last_exim_id; WHILE var_no_more_addresses = 0 DO IF var_curr_address REGEXP '\\*@.+' = 1 THEN SET var_curr_address = CONCAT(arg_local_part, SUBSTRING(var_curr_address, 2)); END IF; IF var_curr_address IS NOT NULL AND LOCATE(var_curr_address, result_addresses) = 0 AND LENGTH(var_curr_address) > 5 THEN SET result_addresses = CONCAT(result_addresses, var_curr_address, '\n'); IF LENGTH(arg_exim_id) > 0 AND (var_curr_last_exim_id IS NULL OR var_curr_last_exim_id <> arg_exim_id) THEN UPDATE exim_forward SET fw_count = fw_count+1, last_exim_id = arg_exim_id WHERE id = var_curr_id; END IF; END IF; FETCH cur_fw_select INTO var_curr_address, var_curr_id, var_curr_last_exim_id; END WHILE; CLOSE cur_fw_select; SET var_no_more_addresses = 0; RETURN result_addresses; END// DELIMITER ;
Az UDF-ek szintaktikája minimálisan különbözik a tárolt eljárásokétól:
CREATE [DEFINER = { user | CURRENT_USER }] FUNCTION sp_name ([func_parameter[,...]]) RETURNS type [characteristic ...] routine_body
A paraméterlista mint látható a fenti kódban "név TIPUS" felsorolás, ahol a típus bármely MySQL adattípus lehet. Ez igaz a visszatérési értékre is (RETURNS TIPUS).
Nekünk jelen esetben szükségünk lesz az eredeti e-mail cím local_part és domain részeire, illetőleg a már korábban említett exim által generált azonosítóra.
Én következetesen használok prefix-eket a változók megkülönböztetésére, így sokkal olvashatóbb és átláthatóbb lesz a kód. Az UDF paramétereit arg, az általam deklarált változókat pedig var prefixekkel látom el.
A characteristic rész a következőket tartalmazhatja:
COMMENT 'string' | LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER }
Ez a rész azonban a MySQL számára csak jelzésértékű információkat tartalmaz, azok hatására a függvény vagy tárolt eljárás futása, eredménye nem változik. Éppen ezért ez a characteristic rész opcionális, akár el is hagyható teljes egészében.
A felsorolt információk szerintem egyértelműek, egyedül a DETERMINISTIC rész lehet idegen, ami csupán annyit árul el, hogy az UDF azonos paraméterek mellett ugyanazt az eredményt fogja-e prezentálni vagy sem.
Rutin törzs...
Először is deklaráljuk a későbbiekben használt változóinkat, kurzorainkat handlereinket.
Amit a kurzorokról tudni kell:
MySQL-ben használhatunk kurzorokat tárolt eljárásokban, függvényekben és triggerekben egyaránt. Segítségükkel egy lekérdezés eredményeként visszatérő eredményhalmazon iterálhatunk végig. A kurzorokkal csak egy irányba haladhatsz, nem hagyhatsz ki sorokat és nem léphetsz visszafelé (Non-scrollable). Nyitott kurzornál ne módosítsd a táblát, különben megbízhatatlan eredményt fogsz kapni (Asensitive).
Kurzorok előtt csak a deklarációs rész állhat, nem SET-elhetünk példának okáért változókat. Ezért is van a fenti kódban az, hogy bár az előzőleg deklarált változókat használjuk a kurzorban, azoknak az értékét csak a kurzor deklaráció után állítjuk be. Ezeknek az értékeknek a feltöltése a kurzorban úgyis csak annak a megnyitása során történik meg.
Kurzorok használatához a következő parancsokat kell ismernünk.
Először is deklarálnunk kell azt:
DECLARE cursor_name CURSOR FOR SELECT_statement;
Következő lépésként meg kell nyitnunk a kurzort az OPEN paranccsal, mielőtt eredményeket szeretnénk lekérdezni:
OPEN cursor_name;
Lekérdezni a kurzorként deklarált SELECT következő sorát, és tovább lépni az azt követőre a FETCH paranccsal lehet:
FETCH cursor_name INTO variable list;
A variable list azaz a változólista annyit tesz, hogy a kurzor által deklarált SELECT-ben lekérdezett mezők mely változókat töltsék fel értékkel. Fontos, hogy minden lekérdezett mezőhöz tartoznia kell egy változónak, különben panaszkodni fog a MySQL, hogy nem stimmel a változók száma.
Végül pedig a nyitott kurzort le kell zárni, hogy deaktiválódjon, és felszabadítsuk a memóriát ami az adott kurzorhoz lett lefoglalva.
CLOSE cursor_name;
Az egyik legfontosabb pontja a kurzorok használatának a NOT FOUND handlerek deklarálása, a lekérdezésünk "no data to fetch" eredményének lekezelésére:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET var_no_more_addresses = 1;
Fontos, hogy ezzel nem azt mondtuk, hogy a var_no_more_addresses kezdőértéke 1, hanem azt, ha a FETCH utasítás nem ad vissza eredményt, ezt a változót állítsa 1-re! Ergo magát a változót előbb deklarálnunk kell (ahogy ezt meg is tettük), és vagy inicializáljuk azt, vagy nem.
A mi kurzorunk egy olyan lekérdezés eredményét adja, amiben lekérdezzük a célcímeket konkrét e-mail illetve domain (*@domain) alapján.
A 18. 19. sorokban összeállítottuk magát az eredeti e-mail címet, és a domainhez szükséges joker címet, a későbbi egyszerűbb használat érdekében.
No itt jön a kurzor, amit megnyitunk, majd a soron következő eredményeket a korábban deklarált változókba töltjük, és elkezdünk végig iterálni a sorokon a kurzorunk segítségével.
Mint látható, a WHILE egy elöltesztelős ciklus, aminek nincs hátultesztelős verziója. Ha ilyet szeretnénk, akkor a REPEAT-et kell használnunk:
domain_iterate: REPEAT [ciklus_torzs] UNTIL var_no_more_addresses = 1 END REPEAT domain_iterate;
Az első FETCH utasítás azért a ciklus előtt van kiadva, mivel abba már csak akkor szeretnénk belekezdeni (és addig iterálni) ha (amíg) van eredmény.
A 25-27. sorokban ellenőrizzük a célcímet. Amennyiben az egy joker e-mail, az azt jelenti, hogy az új funkcionalitásról van szó, azaz egy komplett domaint irányítunk át egy másik domainre, megtartva a címzettet. Ebben az esetben a * helyére behelyettesítjük az eredeti postafiók nevet. Így valósul meg a barmi@teszt.hu -> barmi@teszt2.hu
A következő lépéseket csak akkor csináljuk meg, ha az aktuálisan megkapott célcím nem NULL, nem szerepel még az eredménylistában és a hossza nagyobb mint 5 karakter (6 karakteres a@a.hu mint legrövidebb előfordulási lehetőség)
Ha ezeknek a feltételeknek megfelel az e-mail cím amit kaptunk, hozzáfűzzük az eredménylistához újsor karakterrel a végén.
A 31-33. sor tartalmazza egyrészről a forwardolás tényének rögzítését, másrészről pedig a korábban említett ellenőrzést az exim_id alapján. Csak akkor számoljuk el a lekérdezést tényleges továbbításnak, ha van exim_id, és nem egyezik az előző exim_id -vel. Ekkor mondhatjuk csak ugyanis, hogy az exim ténylegesen a címlistára kíváncsi, hogy hova küldje a beérkező levelet (mint korábban említettem, első alkalommal csak megkérdezi, hogy van-e mivel foglalkoznia, akkor még exim_id sincs).
Mindezeket követően még a cikluson belül tovább kell löknünk a kurzort a következő rekordra. Amennyiben ennek not found az eredménye, a not found handlerünk a var_no_more_addresses értékét 1-re állítja, így a ciklusunk a végéhez ért.
A lefutott ciklus után lezárjuk a kurzort, a var_no_more_addresses értékét visszaállítjuk 0-ra, és visszatérünk a leválogatott e-mail címekkel amik külön sorokban szerepelnek, és fel tudja őket dolgozni az exim.
A függvényünk már készen van, be is töltöttük a MySQL-be, de még az eximet meg kell tanítanunk rá, hogy használja is. Ehhez módosítanunk kell a lookup-ot a userforward-ban:
userforward: local_parts = !default driver = redirect data = ${lookup mysql{select get_forwardset('${quote_mysql:$local_part}', '${quote_mysql:$domain}', '${quote_mysql:$message_exim_id}')}{$value}fail} check_ancestor
Ugye nem is volt bonyolult :D
Próbáljuk is ki. Először vegyünk fel egy új rekordot az exim_forward táblánkba:
INSERT INTO `exim_forward` (`email`, `newaddress`, `fw_count`) VALUES ('nullstring@teszt.hu', 'nullstring@teszt2.hu', '0');
Majd küldjünk egy e-mailt a nullstring@teszt.hu címre, amit a nullstring@teszt2.hu címen szeretnénk ha landolna, és nézzük mit csinál az exim:
2011-12-31 02:20:18 SMTP connection from [74.125.82.51] (TCP/IP connection count = 1)
2011-12-31 02:20:41 1Rgncn-0008ER-1R <= felado@felado.hu H=mail-ww0-f51.google.com [74.125.82.51] P=esmtp S=1552 id=CAGpH1bo4nR4Ju+GSH_h4cFPxJChTQ4vWpbgih2Yop=aJcPJvtA@mail.gmail.com T="fw-teszt" from <felado@felado.hu> for nullstring@teszt.hu
2011-12-31 02:20:41 1Rgncn-0008ER-1R => nullstring@teszt2.hu <nullstring@teszt.hu> R=lookuphost T=remote_smtp H=gmail-smtp-in.l.google.com [173.194.65.27] X=TLS1.0:RSA_ARCFOUR_SHA1:16 C="250 2.0.0 OK 1325294463 w45si16840104eeh.4" DT=0s
2011-12-31 02:20:41 1Rgncn-0008ER-1R Completed
2011-12-31 02:21:11 SMTP connection from mail-ww0-f51.google.com [74.125.82.51] closed by QUIT
Egyértelműen látható, hogy a felado@felado.hu -tól érkező nullstring@teszt.hu címre küldött levél esetén sikeresen lekérdezte az új e-mail címet, és arra tovább is küldte a levelet.
Nade fel is jegyezte ennek a tényét?
mysql> select * from exim_forward; +----+---------------------+----------------------+----------+------------------+ | id | email | newaddress | fw_count | last_exim_id | +----+---------------------+----------------------+----------+------------------+ | 1 | nullstring@teszt.hu | nullstring@teszt2.hu | 1 | 1Rgncn-0008ER-1R | +----+---------------------+----------------------+----------+------------------+ 1 rows in set (0.00 sec)
Úgy tűnik igen, hiszen az fw_count értéke immáron 1. Az exim által generált azonosító is helyesen lett letárolva, így nincs más hátra mint előre,
ugorjunk bele a szilveszterbe! :D
BUÉK!
Nincsenek megjegyzések:
Megjegyzés küldése