1<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 4<html> 5 6<head> 7 8<title>Postfix After-Queue Content Filter </title> 9 10<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> 11 12</head> 13 14<body> 15 16<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix After-Queue Content Filter </h1> 17 18<hr> 19 20<h2>Introduction</h2> 21 22<p> This document requires Postfix version 2.1 or later. </p> 23 24<p> Normally, Postfix receives mail, stores it in the mail queue 25and then delivers it. With the external content filter described 26here, mail is filtered AFTER it is queued. This approach decouples 27mail receiving processes from mail filtering processes, and gives 28you maximal control over how many filtering processes you are 29willing to run in parallel. </p> 30 31<p> The after-queue content filter is meant to be used as follows: </p> 32 33<blockquote> 34 35<table> 36 37<tr> 38 39 <td bgcolor="#f0f0ff" align="center" valign="middle"> 40 Network or<br> local users </td> 41 42 <td align="center" valign="middle"> <tt> -> </tt> </td> 43 44 <td bgcolor="#f0f0ff" align="center" valign="middle"> 45 Postfix<br> queue </td> 46 47 <td align="center" valign="middle"> <tt> -> </tt> </td> 48 49 <td bgcolor="#f0f0ff" align="center" valign="middle"> 50 <b>Content<br> filter</b> </td> 51 52 <td align="center" valign="middle"> <tt> -> </tt> </td> 53 54 <td bgcolor="#f0f0ff" align="center" valign="middle"> 55 Postfix<br> queue </td> 56 57 <td align="center" valign="middle"> <tt> -> </tt> </td> 58 59 <td bgcolor="#f0f0ff" align="center" valign="middle"> 60 Network or<br> local mailbox </td> 61 62</tr> 63 64</table> 65 66</blockquote> 67 68<p> This document describes implementations that use a single 69Postfix instance for everything: receiving, filtering and delivering 70mail. Applications that use two separate Postfix instances will 71be covered by a later version of this document. </p> 72 73<p> The after-queue content filter is not to be confused with the 74approaches described in the SMTPD_PROXY_README or MILTER_README 75documents, 76where incoming SMTP mail is filtered BEFORE it is stored into the 77Postfix queue. </p> 78 79<p> This document describes two approaches to content filter 80all email, as well as several options to filter mail selectively: </p> 81 82<ul> 83 84<li><a href="#principles">Principles of operation</a> 85 86<li>Simple content filter 87 88<ul> 89 90<li><a href="#simple_filter">Simple content filter example</a> 91 92<li><a href="#simple_performance">Simple content filter performance</a> 93 94<li><a href="#simple_limitations">Simple content filter limitations</a> 95 96<li><a href="#simple_turnoff">Turning off the simple content filter</a> 97 98</ul> 99 100<li>Advanced content filter 101 102<ul> 103 104<li><a href="#advanced_filter">Advanced content filter example</a> 105 106<li><a href="#performance">Advanced content filter performance</a> 107 108<li><a href="#advanced_turnoff">Turning off the advanced content filter</a> 109 110</ul> 111 112<li>Selective content filtering 113 114<ul> 115 116<li><a href="#remote_only">Filtering mail from outside users only</a> 117 118<li><a href="#domain_dependent">Different filters for different domains</a> 119 120<li><a href="#dynamic_filter">FILTER actions in access or header/body tables</a> 121 122</ul> 123 124</ul> 125 126 127<h2><a name="principles">Principles of operation</a> </h2> 128 129<p> An after-queue content filter receives unfiltered mail from Postfix 130(as described further below) and can do one of the following: </p> 131 132<ol> 133 134<li> <p> Re-inject the mail back into Postfix, perhaps after changing 135 content and/or destination. </p> 136 137<li> <p> Discard or quarantine the mail. </p> 138 139<li> <p> Reject the mail (by sending a suitable status code back to 140 Postfix). Postfix will send the mail back to the sender address. </p> 141 142</ol> 143 144<p> NOTE: in this time of mail worms and forged spam, it is a VERY 145BAD IDEA to send viruses back to the sender address, because the 146sender address is almost certainly not the originator. It is better 147to discard known viruses, and to quarantine material that is 148suspect so that a human can decide what to do with it. </p> 149 150<h2><a name="simple_filter">Simple content filter example</a></h2> 151 152<p> The first example is simple to set up, but has major limitations 153that will be addressed in a second example. Postfix receives 154unfiltered mail from the network with the smtpd(8) server, and 155delivers unfiltered mail to a content filter with the Postfix 156pipe(8) delivery agent. The content filter injects filtered mail 157back into Postfix with the Postfix sendmail(1) command, so that 158Postfix can deliver it to the final destination. </p> 159 160<p> This means that mail submitted via the Postfix sendmail(1) 161command cannot be content filtered. </p> 162 163<p> In the figure below, names followed by a number represent 164Postfix commands or daemon programs. See the OVERVIEW 165document for an introduction to the Postfix architecture. </p> 166 167<blockquote> 168 169<table> 170 171<tr> 172 173 <td align="center" valign="top"> Unfiltered<br> <br> </td> 174 175 <td align="center" valign="top"> <tt> -></tt><br> <br> </td> 176 177 <td bgcolor="#f0f0ff" align="center" valign="middle"> 178 smtpd(8)<br> <br> pickup(8) </td> 179 180 <td align="center" valign="middle"> <tt> >- </tt> </td> 181 182 <td bgcolor="#f0f0ff" align="center" valign="middle"> 183 cleanup(8) </td> 184 185 <td align="center" valign="middle"> <tt> -> </tt> </td> 186 187 <td bgcolor="#f0f0ff" align="center" valign="middle"> 188 qmgr(8)<br> Postfix <br> queue </td> 189 190 <td align="center" valign="middle"> <tt> -< </tt> </td> 191 192 <td bgcolor="#f0f0ff" align="center" valign="middle"> 193 local(8)<br> smtp(8)<br> pipe(8) </td> 194 195 <td align="center" valign="top"> <tt> -></tt><br> <tt> 196 -></tt><br> </td> 197 198 <td align="center" valign="top"> Filtered<br> Filtered<br> 199 </td> 200 201</tr> 202 203<tr> 204 205 <td colspan="2"> </td> 206 207 <td align="center" valign="middle"> ^<br> <tt> | </tt> </td> 208 209 <td colspan="5"> </td> 210 211 <td align="center" valign="middle"> <tt> |<br> v </tt> </td> 212 213 <td colspan="2"> </td> 214 215</tr> 216 217<tr> 218 219 <td colspan="2"> </td> 220 221 <td bgcolor="#f0f0ff" align="center" valign="middle"> 222 <a href="QSHAPE_README.html#maildrop_queue"> maildrop <br> 223 queue </a> </td> 224 225 <td align="center" valign="middle"> <tt> <- </tt> </td> 226 227 <td bgcolor="#f0f0ff" align="center" valign="middle">Postfix<br> 228 postdrop(1) </td> 229 230 <td align="center" valign="middle"> <tt> <- </tt> </td> 231 232 <td bgcolor="#f0f0ff" align="center" valign="middle">Postfix<br> 233 sendmail(1) </td> 234 235 <td align="center" valign="middle"> <tt> <- </tt> </td> 236 237 <td bgcolor="#f0f0ff" align="center" valign="middle">Content 238 <br> filter </td> 239 240 <td colspan="2"> </td> 241 242</tr> 243 244</table> 245 246</blockquote> 247 248<p> The content filter can be a simple shell script like this: </p> 249 250<blockquote> 251<pre> 252 1 #!/bin/sh 253 2 254 3 # Simple shell-based filter. It is meant to be invoked as follows: 255 4 # /path/to/script -f sender recipients... 256 5 257 6 # Localize these. The -G option does nothing before Postfix 2.3. 258 7 INSPECT_DIR=/var/spool/filter 259 8 SENDMAIL="/usr/sbin/sendmail -G -i" # NEVER NEVER NEVER use "-t" here. 260 9 26110 # Exit codes from <sysexits.h> 26211 EX_TEMPFAIL=75 26312 EX_UNAVAILABLE=69 26413 26514 # Clean up when done or when aborting. 26615 trap "rm -f in.$$" 0 1 2 3 15 26716 26817 # Start processing. 26918 cd $INSPECT_DIR || { 27019 echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; } 27120 27221 cat >in.$$ || { 27322 echo Cannot save mail to file; exit $EX_TEMPFAIL; } 27423 27524 # Specify your content filter here. 27625 # filter <in.$$ || { 27726 # echo Message content rejected; exit $EX_UNAVAILABLE; } 27827 27928 $SENDMAIL "$@" <in.$$ 28029 28130 exit $? 282</pre> 283</blockquote> 284 285<p> Notes: </p> 286 287<ul> 288 289<li> <p> Line 8: The -G option says the filter output is not a local 290mail submission: don't do silly things like appending the local 291domain name to addresses in message headers. This option does 292nothing before Postfix version 2.3. </p> 293 294<li> <p> Line 8: The -i option says don't stop reading input when 295a line contains "." only. </p> 296 297<li> <p> Line 8: NEVER NEVER NEVER use the "-t" command-line option 298here. It will mis-deliver mail, like sending messages from a mailing 299list back to the mailing list. </p> 300 301<li> <p> Line 21: The idea is to first capture the message to 302file and then run the content through a third-party content filter 303program. </p> 304 305<li> <p> Line 22: If the message cannot be captured to file, mail 306delivery is deferred by terminating with exit status 75 (EX_TEMPFAIL). 307Postfix places the message in the deferred mail queue and tries 308again later. </p> 309 310<li> <p> Line 25: You will need to specify a real content filter 311program here that receives the content on standard input. </p> 312 313<li> <p> Line 26: If the content filter program finds a problem, 314the mail is bounced by terminating with exit status 69 (EX_UNAVAILABLE). 315Postfix will send the message back to the sender as undeliverable 316mail. 317</p> 318 319<li> <p> NOTE: in this time of mail worms and spam, it is a BAD 320IDEA to send known viruses or spam back to the sender, because that 321address is likely to be forged. It is safer to discard known viruses 322and to quarantine suspicious content so that it can 323be inspected by a human being. </p> 324 325<li> <p> Line 28: If the content is OK, it is given as input to 326the Postfix sendmail command, and the exit status of the filter 327command is whatever exit status the Postfix sendmail command 328produces. Postfix will deliver the message as usual. </p> 329 330<li> <p> Line 30: Postfix returns the exit status of the Postfix 331sendmail command. </p> 332 333</ul> 334 335<p> I suggest that you first run this script by hand until you are 336satisfied with the results. Run it with a real message (headers+body) 337as input: </p> 338 339<blockquote> 340<pre> 341% /path/to/script -f sender -- recipient... <message-file 342</pre> 343</blockquote> 344 345<p> Once you're satisfied with the content filtering script: </p> 346 347<ul> 348 349<li> <p> Create a dedicated local user account called "filter". This 350user handles all potentially dangerous mail content - that is 351why it should be a separate account. Do not use "nobody", and 352most certainly do not use "root" or "postfix". </p> 353 354<li> <p> Create a directory /var/spool/filter that is accessible only 355to the "filter" user. This is where the content filtering script 356is supposed to store its temporary files. </p> 357 358<li> <p> Configure Postfix to deliver mail to the content filter 359with the pipe(8) delivery agent (see the pipe(8) manpage for a 360description of the command syntax below). </p> 361 362<pre> 363/etc/postfix/master.cf: 364 # ============================================================= 365 # service type private unpriv chroot wakeup maxproc command 366 # (yes) (yes) (yes) (never) (100) 367 # ============================================================= 368 filter unix - n n - 10 pipe 369 flags=Rq user=filter null_sender= 370 argv=/path/to/script -f ${sender} -- ${recipient} 371</pre> 372 373<p> This runs up to 10 content filters in parallel. Instead of a 374limit of 10 concurrent processes, use whatever process limit is 375feasible for your machine. Content inspection software can gobble 376up a lot of system resources, so you don't want to have too much 377of it running at the same time. The empty null_sender setting is 378required with Postfix 2.3 and later. </p> 379 380<li> <p> To turn on content filtering for mail arriving via SMTP 381only, append "-o content_filter=filter:dummy" to the master.cf 382entry that defines the Postfix SMTP server: </p> 383 384<pre> 385/etc/postfix/master.cf: 386 # ============================================================= 387 # service type private unpriv chroot wakeup maxproc command 388 # (yes) (yes) (yes) (never) (100) 389 # ============================================================= 390 smtp inet ...other stuff here, do not change... smtpd 391 -o content_filter=filter:dummy 392</pre> 393 394<p> The "-o content_filter" line causes Postfix to add one content 395filter request record to each incoming mail message, with content 396"filter:dummy". This record overrides the normal mail routing 397and causes mail to be given to the content filter instead. </p> 398 399<p> The content_filter configuration parameter expects a value of 400the form <i>transport:destination</i>. The <i>transport</i> name 401specifies the first field of a mail delivery agent definition in 402master.cf; the syntax of the next-hop <i>destination</i> is described 403in the manual page of the corresponding delivery agent. </p> 404 405<p> The meaning of an empty next-hop filter <i>destination</i> is 406version dependent. Postfix 2.7 and later will use the recipient 407domain; earlier versions will use $myhostname. Specify 408"default_filter_nexthop = $myhostname" for compatibility with Postfix 4092.6 or earlier, or specify a non-empty next-hop filter <i>destination</i>. 410</p> 411 412<p> The content_filter setting has lower precedence than a FILTER 413action that is specified in an access(5), header_checks(5) or 414body_checks(5) table. </p> 415 416<li> <p> Execute "<b>postfix reload</b>" to complete the change. 417</p> 418 419</ul> 420 421<h2> <a name="simple_performance">Simple content filter performance</a> </h2> 422 423<p> With the shell script as shown above you will lose a factor of 424four in Postfix performance for transit mail that arrives and leaves 425via SMTP. You will lose another factor in transit performance for 426each additional temporary file that is created and deleted in the 427process of content filtering. The performance impact is less for 428mail that is submitted or delivered locally, because such deliveries 429are already slower than SMTP transit mail. </p> 430 431<h2><a name="simple_limitations">Simple content filter limitations</a></h2> 432 433<p> The problem with content filters like the one above is that 434they are not very robust. The reason is that the software does not 435talk a well-defined protocol with Postfix. If the filter shell 436script aborts because the shell runs into some memory allocation 437problem, the script will not produce a nice exit status as defined 438in the file /usr/include/sysexits.h. Instead of going to the 439deferred queue, mail will bounce. The same lack of robustness can 440happen when the content filtering software itself runs into a 441resource problem. </p> 442 443<p> The simple content filter method is not suitable for content 444filter actions that are invoked via header_checks or body_checks 445patterns. These patterns will be applied again after mail is 446re-injected with the Postfix sendmail command, resulting in a mail 447filtering loop. The advanced content filtering method (see below) 448makes it possible to turn off header_checks or body_checks patterns 449for filtered mail. </p> 450 451<h2><a name="simple_turnoff">Turning off the simple content filter</a> </h2> 452 453<p> To turn off "simple" content filtering: </p> 454 455<ul> <li> <p> Edit the master.cf file, remove the "-o 456content_filter=filter:dummy" text from the entry that defines the 457Postfix SMTP server. </p> 458 459<li> <p> Execute "<b>postsuper -r ALL</b>" to remove content 460filter request records from existing queue files. </p> 461 462<li> <p> Execute another "<b>postfix reload</b>". </p> 463 464</ul> 465 466<h2><a name="advanced_filter">Advanced content filter example</a></h2> 467 468<p> The second example is more complex, but can give better 469performance, and is less likely to bounce mail when the machine 470runs into some resource problem. This content filter receives 471unfiltered mail with SMTP on localhost port 10025, and sends filtered 472mail back into Postfix with SMTP on localhost port 10026. </p> 473 474<p> For non-SMTP capable content filtering software, Bennett Todd's 475SMTP proxy implements a nice PERL/SMTP content filtering framework. 476See: http://bent.latency.net/smtpprox/. </p> 477 478<p> In the figure below, names followed by a number represent 479Postfix commands or daemon programs. See the OVERVIEW 480document for an introduction to the Postfix architecture. </p> 481 482<blockquote> 483 484<table> 485 486<tr> 487 488 <td align="center" valign="middle"> Unfiltered<br> <br> 489 Unfiltered</td> 490 491 <td align="center" valign="middle"> <tt> -></tt><br> <br> 492 <tt> -> </tt> </td> 493 494 <td bgcolor="#f0f0ff" align="center" valign="middle"> 495 smtpd(8)<br> <br> pickup(8) </td> 496 497 <td align="center" valign="middle"> <tt> >- </tt> </td> 498 499 <td bgcolor="#f0f0ff" align="center" valign="middle"> 500 cleanup(8) </td> 501 502 <td align="center" valign="middle"> <tt> -> </tt> </td> 503 504 <td bgcolor="#f0f0ff" align="center" valign="middle"> 505 qmgr(8)<br> Postfix <br> queue </td> 506 507 <td align="center" valign="middle"> <tt> -< </tt> </td> 508 509 <td bgcolor="#f0f0ff" align="center" valign="middle"> 510 smtp(8)<br> <br> local(8) </td> 511 512 <td align="center" valign="middle"> <tt> -></tt><br> <br> 513 <tt> -> </tt></td> 514 515 <td align="center" valign="middle"> Filtered<br> <br> 516 Filtered</td> 517 518</tr> 519 520<tr> 521 522 <td colspan="4"> </td> 523 524 <td align="center" valign="middle"> ^<br> <tt> | </tt> </td> 525 526 <td> </td> 527 528 <td align="center" valign="middle"> <tt> |<br> v </tt> </td> 529 530 <td colspan="4"> </td> 531 532</tr> 533 534<tr> 535 536 <td colspan="4"> </td> 537 538 <td bgcolor="#f0f0ff" align="center" valign="middle"> 539 smtpd(8)<br> 10026 </td> 540 541 <td> </td> 542 543 <td bgcolor="#f0f0ff" align="center" valign="middle"> 544 smtp(8)<br> </td> 545 546 <td colspan="4"> </td> 547 548</tr> 549 550<tr> 551 552 <td colspan="4"> </td> 553 554 <td align="center" valign="middle"> ^<br> <tt> | </tt> </td> 555 556 <td> </td> 557 558 <td align="center" valign="middle"> <tt> |<br> v </tt> </td> 559 560 <td colspan="4"> </td> 561 562</tr> 563 564<tr> 565 566 <td colspan="4"> </td> 567 568 <td colspan="3" bgcolor="#f0f0ff" align="center" 569 valign="middle">content filter 10025</td> 570 571 <td colspan="4"> </td> 572 573</tr> 574 575</table> 576 577</blockquote> 578 579<p> The example given here filters all mail, including mail that 580arrives via SMTP and mail that is locally submitted via the Postfix 581sendmail command (local submissions enter Postfix via the pickup(8) 582server; to keep the figure simple we omit local submission details). 583See examples near the end of this document for 584how to exclude local users from filtering, or how to configure a 585destination dependent content filter. </p> 586 587<p> You can expect to lose about a factor of two in Postfix 588performance for mail that arrives and leaves via SMTP, provided 589that the content filter creates no temporary files. Each temporary 590file created by the content filter adds another factor to the 591performance loss. </p> 592 593<h3>Advanced content filter: requesting that all mail is filtered</h3> 594 595<p> To enable the advanced content filter method for all mail, 596specify in main.cf: </p> 597 598<blockquote> 599<pre> 600/etc/postfix/main.cf: 601 content_filter = scan:localhost:10025 602 receive_override_options = no_address_mappings 603</pre> 604</blockquote> 605 606<ul> 607 608<li> <p> The "receive_override_options" line disables address 609manipulation before the content filter, so that the content filter 610sees the original mail addresses instead of the result of virtual 611alias expansion, canonical mapping, automatic bcc, address 612masquerading, etc. </p> 613 614<li> <p> The "content_filter" line causes Postfix to add one content 615filter request record to each incoming mail message, with content 616"scan:localhost:10025". The content filter request records are 617added by the smtpd(8) and pickup(8) servers (and qmqpd(8) if you 618decide to enable this service). </p> 619 620<li> <p> Content filter requests are stored in queue files; this 621is how Postfix keeps track of what mail needs filtering. When a 622queue file contains a content filter request, the queue manager 623will deliver the mail to the specified content filter regardless 624of its final destination. </p> 625 626<li> <p> The content_filter configuration parameter expects a value 627of the form <i>transport:destination</i>. The <i>transport</i> name 628specifies the first field of a mail delivery agent definition in 629master.cf; the syntax of the next-hop <i>destination</i> is described 630in the manual page of the corresponding delivery agent. </p> 631 632<li> <p> The meaning of an empty next-hop filter <i>destination</i> 633is version dependent. Postfix 2.7 and later will use the recipient 634domain; earlier versions will use $myhostname. Specify 635"default_filter_nexthop = $myhostname" for compatibility with Postfix 6362.6 or earlier, or specify a non-empty next-hop filter <i>destination</i>. 637 638<li> <p> The content_filter setting has lower precedence than a 639FILTER action that is specified in an access(5), header_checks(5) 640or body_checks(5) table. </p> 641 642</ul> 643 644<h3> Advanced content filter: sending unfiltered mail to the content 645filter</h3> 646 647<p> In this example, "scan" is an instance of the Postfix SMTP 648client with slightly different configuration parameters. This is 649how one would set up the service in the Postfix master.cf file: 650</p> 651 652<blockquote> 653<pre> 654/etc/postfix/master.cf: 655 # ============================================================= 656 # service type private unpriv chroot wakeup maxproc command 657 # (yes) (yes) (yes) (never) (100) 658 # ============================================================= 659 scan unix - - n - 10 smtp 660 -o smtp_send_xforward_command=yes 661 -o disable_mime_output_conversion=yes 662 -o smtp_generic_maps= 663</pre> 664</blockquote> 665 666<ul> 667 668<li> <p> This runs up to 10 content filters in parallel. Instead 669of a limit of 10 concurrent processes, use whatever process limit 670is feasible for your machine. Content inspection software can 671gobble up a lot of system resources, so you don't want to have too 672much of it running at the same time. </p> 673 674<li> <p> With "-o smtp_send_xforward_command=yes", the scan transport 675will try to forward the original client name and IP address 676through the content filter to the 677after-filter smtpd process, so that filtered mail is logged with 678the real client name IP address. See smtp(8) and XFORWARD_README 679for more information. </p> 680 681<li> <p> The "-o disable_mime_output_conversion=yes" is a workaround 682that prevents the breaking of domainkeys and other digital signatures. 683This is needed because some SMTP-based content filters don't announce 6848BITMIME support, even though they can handle 8-bit mail. </p> 685 686<li> <p> The "-o smtp_generic_maps=" is a workaround that prevents 687local address rewriting with generic(5) maps. Such rewriting should 688happen only when mail is sent out to the Internet. </p> 689 690</ul> 691 692<h3>Advanced content filter: running the content filter</h3> 693 694<p> The content filter can be set up with the Postfix spawn service, 695which is the Postfix equivalent of inetd. For example, to instantiate 696up to 10 content filtering processes on localhost port 10025: </p> 697 698<blockquote> 699<pre> 700/etc/postfix/master.cf: 701 # =================================================================== 702 # service type private unpriv chroot wakeup maxproc command 703 # (yes) (yes) (yes) (never) (100) 704 # =================================================================== 705 localhost:10025 inet n n n - 10 spawn 706 user=filter argv=/path/to/filter localhost 10026 707</pre> 708</blockquote> 709 710<ul> 711 712<li> <p> "filter" is a dedicated local user account. The user will 713never log in, and can be given a "*" password and non-existent 714shell and home directory. This user handles all potentially 715dangerous mail content - that is why it should be a separate account. 716</p> 717 718<li> <p> By default, Postfix will terminate a command that runs 719longer than command_time_limit seconds (default: 1000s). This is a 720safety measure that prevents filters from running forever. </p> 721 722</ul> 723 724<p> If you want to have your filter listening on port localhost:10025 725instead of Postfix, then you must run your filter as a stand-alone 726program, and must not use the Postfix spawn service. </p> 727 728<h3>Advanced filter: injecting mail back into Postfix</h3> 729 730<p> The job of the content filter is to either bounce mail with a 731suitable diagnostic, or to feed the mail back into Postfix through 732a dedicated listener on port localhost 10026. </p> 733 734<p> The simplest content filter just copies SMTP commands and data 735between its inputs and outputs. If it has a problem, all it has to 736do is to reply to an input of `.' from Postfix with `550 content 737rejected', and to disconnect without sending `.' on the connection 738that injects mail back into Postfix. </p> 739 740<blockquote> 741<pre> 742/etc/postfix/master.cf: 743 # =================================================================== 744 # service type private unpriv chroot wakeup maxproc command 745 # (yes) (yes) (yes) (never) (100) 746 # =================================================================== 747 localhost:10026 inet n - n - 10 smtpd 748 -o content_filter= 749 -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_milters 750 -o smtpd_helo_restrictions= 751 -o smtpd_client_restrictions= 752 -o smtpd_sender_restrictions= 753 -o smtpd_recipient_restrictions=permit_mynetworks,reject 754 -o mynetworks=127.0.0.0/8 755 -o smtpd_authorized_xforward_hosts=127.0.0.0/8 756</pre> 757</blockquote> 758 759<ul> 760 761<li> <p> NOTE: do not use spaces around the "=" or "," characters. </p> 762 763<li> <p> NOTE: the SMTP server must not have a smaller process 764limit than the "filter" master.cf entry. </p> 765 766<li> <p> The "-o content_filter=" overrides main.cf settings, and 767requests no content filtering for mail from the content filter. 768This is required or else mail will loop. </p> 769 770<li> <p> The "-o receive_override_options" overrides main.cf settings 771to avoid duplicating work that was already done before the content 772filter. These options are complementary to the options that are 773specified in main.cf: </p> 774 775<ul> 776 777 <li> <p> We specify "no_unknown_recipient_checks" to disable 778 attempts to find out if a recipient is unknown. </p> 779 780 <li> <p> We specify "no_header_body_checks" to disable header/body 781 checks. </p> 782 783 <li> <p> We specify "no_milters" to disable Milter applications 784 (this option is available only in Postfix 2.3 and later). </p> 785 786 <li> <p> We don't specify "no_address_mappings" here. This 787 enables virtual alias expansion, canonical mappings, address 788 masquerading, and other address mappings after the content 789 filter. The main.cf setting of "receive_override_options" 790 disables these mappings before the content filter. </p> 791 792</ul> 793 794 <p> These receive override options are either implemented by the 795 SMTP server itself, or they are passed on to the cleanup server. 796 </p> 797 798<li> <p> The "-o smtpd_xxx_restrictions" and "-o mynetworks=127.0.0.0/8" 799override main.cf settings. They turn off junk mail controls that 800would only waste time here. 801 802<li> <p> With "-o smtpd_authorized_xforward_hosts=127.0.0.0/8", 803the scan transport will try to forward the original client name 804and IP address to the after-filter smtpd process, so that filtered 805mail is logged with the real client name and IP address. See 806XFORWARD_README and smtpd(8). </p> 807 808</ul> 809 810<h2><a name="performance">Advanced content filter performance</a></h2> 811 812<p> With the "sandwich" approach to content filtering described 813here, it is important to match the filter concurrency to the 814available CPU, memory and I/O resources. Too few content filter 815processes and mail accumulates in the active queue even with low 816traffic volume; too much concurrency and Postfix ends up deferring 817mail destined for the content filter because processes fail due to 818insufficient resources. </p> 819 820<p> Currently, content filter performance tuning is a process of 821trial and error; analysis is handicapped because filtered and 822unfiltered messages share the same queue. As mentioned in the 823introduction of this document, content filtering with multiple 824Postfix instances will be covered in a future version. </p> 825 826<h2><a name="advanced_turnoff">Turning off the advanced content filter</a> </h2> 827 828<p> To turn off "advanced" content filtering: </p> 829 830<ul> <li> <p> Delete or comment out the two following main.cf lines. 831The other changes made for advanced content filtering have no effect 832when content filtering is turned off. </p> 833 834<blockquote> 835<pre> 836/etc/postfix/main.cf: 837 content_filter = scan:localhost:10025 838 receive_override_options = no_address_mappings 839</pre> 840</blockquote> 841 842<li> <p> Execute "<b>postsuper -r ALL</b>" to remove content 843filter request records from existing queue files. </p> 844 845<li> <p> Execute another "<b>postfix reload</b>". </p> 846 847</ul> 848 849<h2><a name="remote_only">Filtering mail from outside users only</a></h2> 850 851<p> The easiest approach is to configure ONE Postfix instance with 852multiple SMTP server IP addresses in master.cf: </p> 853 854<ul> 855 856<li> <p> Two SMTP server IP addresses for mail from inside users only, 857with content filtering turned off. </p> 858 859<pre> 860/etc/postfix.master.cf: 861 # ================================================================== 862 # service type private unpriv chroot wakeup maxproc command 863 # (yes) (yes) (yes) (never) (100) 864 # ================================================================== 865 1.2.3.4:smtp inet n - n - - smtpd 866 -o smtpd_client_restrictions=permit_mynetworks,reject 867 127.0.0.1:smtp inet n - n - - smtpd 868 -o smtpd_client_restrictions=permit_mynetworks,reject 869</pre> 870 871<li> <p> One SMTP server address for mail from outside users with 872content filtering turned on. </p> 873 874<pre> 875/etc/postfix.master.cf: 876 # ================================================================= 877 # service type private unpriv chroot wakeup maxproc command 878 # (yes) (yes) (yes) (never) (100) 879 # ================================================================= 880 1.2.3.5:smtp inet n - n - - smtpd 881 -o content_filter=filter-service:filter-destination 882 -o receive_override_options=no_address_mappings 883</pre> 884 885</ul> 886 887<p> After this, you can follow the same procedure as outlined in 888the "advanced" or "simple" content filtering examples above, except 889that you must not specify "content_filter" or "receive_override_options" 890in the main.cf file. </p> 891 892<h2><a name="domain_dependent">Different filters for different 893domains</a></h2> 894 895<p> If you are an MX service provider and want to apply different 896content filters for different domains, you can configure ONE Postfix 897instance with multiple SMTP server IP addresses in master.cf. Each 898address provides a different content filter service. </p> 899 900<blockquote> 901<pre> 902/etc/postfix.master.cf: 903 # ================================================================= 904 # service type private unpriv chroot wakeup maxproc command 905 # (yes) (yes) (yes) (never) (100) 906 # ================================================================= 907 # SMTP service for domains that are filtered with service1:dest1 908 1.2.3.4:smtp inet n - n - - smtpd 909 -o content_filter=service1:dest1 910 -o receive_override_options=no_address_mappings 911 912 # SMTP service for domains that are filtered with service2:dest2 913 1.2.3.5:smtp inet n - n - - smtpd 914 -o content_filter=service2:dest2 915 -o receive_override_options=no_address_mappings 916</pre> 917</blockquote> 918 919<p> After this, you can follow the same procedure as outlined in 920the "advanced" or "simple" content filtering examples above, except 921that you must not specify "content_filter" or "receive_override_options" 922in the main.cf file. </p> 923 924<p> Set up MX records in the DNS that route each domain to the 925proper SMTP server instance. </p> 926 927<h2><a name="dynamic_filter">FILTER actions in access or header/body 928tables</a></h2> 929 930<p> The above filtering configurations are static. Mail that follows 931a given path is either always filtered or it is never filtered. As 932of Postfix 2.0 you can also turn on content filtering on the fly. 933</p> 934 935<p> To turn on content filtering with an access(5) table rule: </p> 936 937<blockquote> 938<pre> 939/etc/postfix/access: 940 <i>whatever</i> FILTER foo:bar 941</pre> 942</blockquote> 943 944<p> To turn on content filtering with a header_checks(5) or 945body_checks(5) table pattern: </p> 946 947<blockquote> 948<pre> 949/etc/postfix/header_checks: 950 /<i>whatever</i>/ FILTER foo:bar 951</pre> 952</blockquote> 953 954<p> You can do this in smtpd access maps as well as the cleanup 955server's header/body_checks. This feature must be used with great 956care: you must disable all the UCE features in the after-filter 957smtpd and cleanup daemons or else you will have a content filtering 958loop. </p> 959 960<p> Limitations: </p> 961 962<ul> 963 964<li> <p> FILTER actions from smtpd access maps and header/body_checks 965take precedence over filters specified with the main.cf content_filter 966parameter. </p> 967 968<li> <p> If a message triggers more than one filter action, only 969the last one takes effect. </p> 970 971<li> <p> The same content filter is applied to all the recipients 972of a given message. </p> 973 974</ul> 975 976</body> 977 978</html> 979