Send spam mail to a special folder using postfix

1,013

Solution 1

Cursory perusal of postfix's local(8) local delivery agent man page shows no hint of this type of capability - as expected. This kind of tasks is usually offloaded to procmail (probably through the mailbox_command directive) which can handle the task you describe while managing your kitchen sink on the side. The downside of procmail is the config file format, the upside the flexibility and the tons of examples that are easily found. If anything better than procmail has recently emerged, I know not.

For my money, though, even if I found the way to shoehorn the MTA in doing what you want, I would not follow that road, because this kind of mail sorting things have a way of balooning and no MTA (that I know of: perhaps exchange does,who knows) can do a good job in also being a flexible message handler/delivery agent.

This is a procmail recipe that woud do what you want based on the sole header content (where DEFAULT is the delivery directory, often something like $HOME/Mail/):

:0
* ^X-Spam-Flag: YES
$DEFAULT/.Spam/

Edit: (This assumes maildir mailbox format, as noted in a comment below. Omit final slash if using mbox)

Solution 2

As Alien Life Form said, this is a job for procmail. That's not a replacement for the mail server's local delivery agent; it's a separate process which will be called after the MDA has done it's work.

Each user that wants to have procmail sort their mail will need to create a file called .forward in their home directory. That file should contain the following:

"|exec /usr/local/bin/procmail || exit 75"

complete with the " sign and all.

ALF has already posted a basic .procmail file that will sort the mail tagged with spam into a separate folder.

Solution 3

What is your mail delivery agent (see main.cf mailbox_command)? If the MDA is dovecot, it supports the Sieve IETF standard (rfc5228), which can do a lot more than procmail without exposing possible security holes. DON'T bolt on procmail to postfix/dovecot, sieve is fully integrated. If you're using Courier, then procmail is an okay solution. However, you will find the sieve/sievec programs from Pigeonhole to be faster and cleaner.

The following is a simple sieve script to recognize your spam header and put the message in the Trash file.

require "fileinto";

if header :comparator "i;ascii-casemap" :contains "Subject" "**SPAM**"  
{
  fileinto "Trash";
  stop;
}
Share:
1,013

Related videos on Youtube

Zyber
Author by

Zyber

.NET developer based in London (and on the lookout for contracts ;-)) (it was worth a try) Interested in all things .NET / Alt.NET but I like to think I can stick my beak into everything.

Updated on September 18, 2022

Comments

  • Zyber
    Zyber over 1 year

    I'm trying to create multiple asynchronous HTTP connections using single client endpoint I have tried the multiplexing example given in Apache site

    the code snippet is as follows,

    final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
                .setSoTimeout(Timeout.ofSeconds(5))
                .build();
    
        final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
                HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig);
    
        client.start();
    
        final HttpHost target = new HttpHost("localhost", 7070, "https");
        final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
        final AsyncClientEndpoint endpoint = leaseFuture.get(30, TimeUnit.SECONDS);
        try {
            final String[] requestUris = new String[] {"/test.html"};
    
            final CountDownLatch latch = new CountDownLatch(requestUris.length);
            for (final String requestUri: requestUris) {
                final SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
                endpoint.execute(
                        SimpleRequestProducer.create(request),
                        SimpleResponseConsumer.create(),
                        new FutureCallback<SimpleHttpResponse>() {
    
                            @Override
                            public void completed(final SimpleHttpResponse response) {
                                latch.countDown();
                                System.out.println(requestUri + "->" + response.getCode());
                                System.out.println(response.getBody());
                            }
    
                            @Override
                            public void failed(final Exception ex) {
                                latch.countDown();
                                System.out.println(requestUri + "->" + ex);
                            }
    
                            @Override
                            public void cancelled() {
                                latch.countDown();
                                System.out.println(requestUri + " cancelled");
                            }
    
                        });
            }
            latch.await();
        } finally {
            endpoint.releaseAndReuse();
        }
    
        System.out.println("Shutting down");
        client.shutdown(ShutdownType.GRACEFUL);
    

    This example works properly for a site which have a valid certificate, but if I want to try a site which certificate is expired/self signed, it throws the following exceptions

    javax.net.ssl.SSLHandshakeException: General SSLEngine problem javax.net.ssl.SSLHandshakeException: General SSLEngine problem at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478) at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535) at sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1214) at sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1186) at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:469) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doWrap(SSLIOSession.java:256) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:294) at org.apache.hc.core5.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:502) at org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:112) at org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50) at org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:173) at org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:123) at org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:80) at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) at java.lang.Thread.run(Thread.java:748) Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) at sun.security.ssl.Handshaker$1.run(Handshaker.java:966) at sun.security.ssl.Handshaker$1.run(Handshaker.java:963) at java.security.AccessController.doPrivileged(Native Method) at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doRunTask(SSLIOSession.java:274) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:331) ... 8 more Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501) ... 16 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) ... 22 more

    What I have tried: I created a socket factory that trusts all certificates and tried setting in connectionManager but that creates a CloseableHttpClient and I think which cannot be used for asynchronous multiplexing, the code is as follows

    SSLContext sslContext = SSLContextBuilder
                    .create()
                    .loadTrustMaterial(new TrustSelfSignedStrategy())
                    .build();
    
            // we can optionally disable hostname verification. 
            // if you don't want to further weaken the security, you don't have to include this.
            HostnameVerifier allowAllHosts = new NoopHostnameVerifier();
    
            // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
            // and allow all hosts verifier.
            SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);
    
            Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create().register("https", connectionFactory).build();
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
            CloseableHttpClient build = HttpClients.custom().setConnectionManager(cm).build();
    

    Kindly let me know if there are any ways or workarounds to ignore self signed certificates in MinimalHttpAsyncClient.

    • Tom Marthenal
      Tom Marthenal about 11 years
      Looks like it might be necessary to use something like maildrop. I am still looking for a way to do this with Postfix's default MDA so I can keep aliases and other postfix features with minimal trouble. I will post my answer when I come up with it.
  • Malfist
    Malfist over 9 years
    Please note that in some cases procmail lives at /usr/bin/procmail, to figure out where it is on your system run which procmail
  • Zyber
    Zyber about 6 years
    Hi oleg, thanks for answering. When I tried this example, I got javax.net.ssl.SSLPeerUnverifiedException: Certificate for <127.0.0.1> doesn't match common name of the certificate subject: *.abc.com I need to verify hostname check also it seems, kindly help me on this Thanks In Advance
  • ok2c
    ok2c about 6 years
    @Zyber Please use NoopHostnameVerifier to disable host name verification. See updated code snippets
  • Jari Turkia
    Jari Turkia almost 5 years
    $DEFAULT/ is not necessary. Helpful for human readability. Also note, that adding a slash at the end will create a Maildir, if using Mbox then omit the slash (see: unix.stackexchange.com/a/132658/241396).