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