I don't know if this is of use to anyone else, but I seem to have been receiving a lot of spam lately in the format From: "quinton passi" <netbrafe@xxxxxxxx> From: "monroe Wineman" <tualrov1952@xxxxxxxxxxxxxxxxxxx> From: "Flora Looker" <Flora-netalegf@xxxxxxxxxxxxxxxx> So I've been using a User Rule as follows: DEF FN@domaincaps LOCAL loop%,uppercount%,end$,letter% end$=FNgetdomain(D$) REM "Vadim Moos" <_mlifrate@xxxxxxxxxxxxx> IF LEN(end$)<1 THEN =FALSE FOR loop%=1 TO LEN(end$) letter%=ASC(MID$(end$,loop%,1)) IF user_uppercase%?letter% = letter% THEN uppercount%+=1 NEXT IF uppercount%=LEN(end$) THEN =TRUE =FALSE I'm afraid it has some dependencies: you have to have set up an uppercase table in PROCUserTest_Initialise (necessary to distinguish easily between [accented] capitals and punctuation) DIM user_uppercase% 255 SYS"Territory_UpperCaseTable",-1 TO ptr% FOR n%=0 TO 252 STEP 4 user_uppercase%!n%=ptr%!n% NEXT n% REM take copy of uppercase table ... and you need FNgetdomain. DEF FNgetdomain(in$) LOCAL ptr%,domain$ ptr%=INSTR(in$,"@") domain$=MID$(in$,ptr%+1) domain$=LEFT$(domain$) REM trim angle brackets =domain$ This is of course not an entirely 'safe' rule, as there is no way to be certain that legitimate users may not have their address specified with the domain section in caps. (Hmmm, might be safer to do the reverse check on the first half as well, i.e. check for lowercase followed by uppercase after the '@'....) I have also been plagued by spam in the format From: "Ora Barajas" <a-anthrs@xxxxxxxxxxxx> Message-ID: <01c877dd$28708680$643b5176@a-anthrs> From: "Jason Randall" <a--shen@xxxxxxxxxx> Message-ID: <01c875ac$15c33b00$9079407d@a--shen> From: "Chase Rosas" <skulduggeryfa4@xxxxxxxxxxxxxxxx> Message-ID: <01c87215$b95fc480$72a543c8@skulduggeryfa4> i.e. where the first part of the address is repeated from the final part of the Message-ID. Again, this pattern is presumably not unique to spam (although most non-spam e-mails seem to have at least one full stop in the final part of the Message-ID, you certainly can't rely on that), but I have yet to see it in any other context. In order to compare two different fields against each other you have to use the FNUserTest_EndOfHeader feature. (The only drawback of this is that the rule seems to get logged simply as "Call EOH" with no way of indicating what conditions triggered it.) You have to use user variables to store the values and then compare them when the end of the header is reached, as there is no way of telling which order the headers will be found in (or even if both will appear at all, although they jolly well ought to!) What I've done is insert a rule Call From: @ username And Message-id: @ domain | mark spam in the format Message-id: xxxnnxx@dhd / From: dhd@xxxxxxx which has no actual effect other than setting the relevant user variables when the relevant headers are encountered - I suspect the use of the "And" is actually a red herring here and the same effect would be obtained by two separate rules Call From: @ username Call Message-id: @ domain Then at the bottom of the Rules file I have Call EOH which performs the actual comparison and deletion once the end of the header has been reached and all possible data recorded. (N.B. Having looked at it, I find the number of dependencies on this one to be excessive - it makes use of procedures shared between a number of different User Rules - so I'm not going to paste in the whole lot unless somebody actually wants me to....) The basic User Rules are extremely simple and always return FALSE for safety: DEF FN@domain user_domain$=FNgetdomain(d$):REM as above =FALSE DEF FN@username LOCAL nick$,mail$,ptr% PROCnameaddress(d$,nick$,mail$) IF LEFT$(mail$,1)="<" THEN mail$=MID$(mail$,2):mail$=LEFT$(mail$) ptr%=INSTR(mail$,"@") user_username$=LEFT$(mail$,ptr%-1) REM preserve this for checking against user_domain$ at end of header =FALSE At the head of the file, I have to remember to clear my user variables for each new e-mail scanned, to prevent unfortunate coincidences: DEF PROCUserTest_NewMessage REM REM Declare LOCAL variables here, BEFORE the LOCAL ERROR line! REM LOCAL ERROR : ON ERROR LOCAL ENDPROC user_username$="" user_domain$="" ENDPROC Then I do a simple comparison in FNUserTest_EndOfHeader: DEF FNUserTest_EndOfHeader REM REM Declare LOCAL variables here. REM IF user_domain$=user_username$ THEN=delete% =FALSE -- Harriet Bazley == Loyaulte me lie == You /really/ don't want to know.