6

Does postfix allow to dynamically change "myhostname" ? I rtfmed a lot but did not found anything qualitative. My installation is a postfix multiple domain, multiple ip (tweaked in master.cf) and multiple dkim sig but the myhostname directive in master.cf isn't included.

That kind of stuff:

192.168.1.12:smtp inet n - n - - smtpd -o myhostname=mail.mail2.com -o smtpd_banner=mail.mail2.com -o smtp_helo_name=mail.mail2.com

Anyway, banner and helo are OK, but myhostname is still the one included in main.cf

3
  • How do you see that myhostname isnt changed? Only in the DKIM or in some other way?
    – thelogix
    Aug 27, 2014 at 11:17
  • Here is a part of headers: Received: from [X.X.X.X] (blabla.coin.com [X.X.X.X]) by mail.mail1.com <- THIS ONE NEVER CHANGE, STILL USING MASTER.CF SETTINGS (Postfix) with ESMTPSA id 648F21012AC;
    – djaunz
    Aug 27, 2014 at 11:22
  • actually, what you're asking is possible. but the correct approach depends upon your version of postfix... so pls update the OP with the version number!
    – violet313
    Sep 1, 2014 at 15:54

2 Answers 2

12

Postfix is highly configurable. so much so that rtfming seems only slightly more advantageous than perusing the source (only joking).

There are in fact numerous ways of dynamically overriding the static configuration. At a very minimum, some understanding of the Postfix workflow is required. this is in the overview.

It is also useful to understand:

  • different Postfix daemons reference different portions of the main.cf static configuration.
  • most built-in Postfix services are customisable;
  • ad-hoc custom services (milters etc) can be plugged into the workflow;
  • if all else fails, multiple Postfix instances can be deployed; each referring to separate main.cf and master.cf static configurations


Per the OP, wrt conditionally sending mail to some external recipients:

Methods of interest are those that are conditional upon either:

  • the smptd listening port
  • the sender domain name

Apparently specifically in this regard, and for reasons that will soon hopefully become clear, Wietse Venema made some *key changes in Postfix 2.7 to do with content filtering &so to summarise:

pre Postfix 2.7 :

where unspecified, the default nexthop destination is $myhostname (ie: localhost).


Postfix 2.7:

where unspecified, the default nexthop destination is the recipient domain.

transport conditional upon sender domain is supported out-of-the-box via the use of sender_dependent_default_transport_maps


This distinction is of issue because there are still folk stuck on pre 2.7 Postfix installs.. ie: for some Red Hat users relying upon the official rpms, then for example, users still on centOS 5x => Postfix 2.3 & for centOS 6x => Postfix 2.6 (but i might be wrong, dyor etc)


Postfix 2.7:

Things got easier! below are a couple of methods.

The first method involves setting up a couple of smtpd daemons listening on different non-standard ports and uses custom transports conditional upon which smtpd port we submit our outbound email to:

  • port 10026 => custom1_smtp
  • port 10027 => custom2_smtp

This is made possible by dynamically defining a custom filter service & overriding the content_filter directive in the smtpd service. the filter is a dummy. we're not really going to be writing & deploying our own custom filter service. instead we just hijack a postfix smtp service instance for the sole purpose of gaining access to and dynamically overriding the myhostname directive before the email is finally pushed out to the wild.

This can only happen in Postfix 2.7 (and maybe subsequent versions above) because the specified transports' default nexthop destination is defined to be the recipient domain. In versions below Postfix 2.7, it is defined as $myhostname and so the email loops back into Postfix, causing it to bork.


The second method is by the book and uses sender_dependent_default_transport_maps to conditionally route our outbound email to a couple more custom-defined transports; and depends upon the sender's domain name:

  • parrots.tld => custom3_smtp:
  • penguins.tld => custom4_smtp:

The sender_dependent_default_transport_maps act like sender_dependent_relayhost_maps but instead of routing outgoing mail from a specified sender domain to a specified destination domain, sender_dependent_default_transport_maps are used to internally route the outgoing mail from a specified sender (domain) to a specified (custom-defined) transport defined in master.cf.


We add the following directive to /etc/postfix/main.cf:

sender_dependent_default_transport_maps = hash:/etc/postfix/sender_transports


Then create the mapping file /etc/postfix/sender_transports:

@parrots.tld    custom3_smtp:
@penguins.tld   custom4_smtp:

&build the database using postmap:

postmap hash:/etc/postfix/sender_transports


Then we define all our custom transports in /etc/postfix/master.cf:

custom4_smtp      unix  -       -       n       -       -        smtp
             -o myhostname=mailer.external.penguins.tld
             -o smtp_bind_address=m.n.o.p
             -o smtp_helo_name=penguins.tld


custom3_smtp      unix  -       -       n       -       -        smtp
             -o myhostname=mailer.external.parrots.tld
             -o smtp_bind_address=i.j.k.l
             -o smtp_helo_name=parrots.tld


custom2_smtp      unix  -       -       n       -       -        smtp
             -o myhostname=mailer.external.cats.tld
             -o smtp_bind_address=e.f.g.h
             -o smtp_helo_name=cats.tld


custom1_smtp      unix  -       -       n       -       -        smtp
             -o myhostname=mailer.external.dogs.tld
             -o smtp_bind_address=a.b.c.d
             -o smtp_helo_name=dogs.tld



# our main internal entry for the dogs site; all outgoing dogs traffic is
# sent to this (non-standard) port and routed to our custom1_smtp transport
10026             inet  n      -        n       -       -        smtpd
             -o myhostname=mailer.internal.dogs.tld
             -o content_filter=custom1_smtp:  


# our main internal entry for the cats site; all outgoing cats traffic is
# sent to this (non-standard) port and routed to our custom2_smtp transport
10027             inet  n      -        n       -       -        smtpd
             -o myhostname=mailer.internal.cats.tld
             -o content_filter=custom2_smtp:  


# default smtpd entry;  outgoing traffic sent to this port (25) will get routed 
# subject to the conditions in our sender_dependent_default_transport_maps file
smtp              inet  n      -        n       -       -        smtpd
             -o myhostname=mailer.internal.tld


# hoorah.
#


before Postfix 2.7 :

The way commonly suggested by the Postfix pixies is to set up multiple Postfix instances.

But here's where an understanding of the Postfix workflow comes in handy.. because by devising a custom-defined Postfix service chain, it is also achievable with just a single Postfix instance. nothing in main.cf needs to be changed. static configuration is dynamically overridable from within the custom service chains we define in master.cf.

Each service reads it's own subset of all the directives residing in the main.cf config. so as we progress along our custom service chain, we can override any settings as may be permitted from within each respective Postfix service in the chain.

(Additionally, note that we could even write our own custom replacement for any of the default Postfix daemons. which is pretty cool).


In /etc/postfix/master.cf:

# each Postfix service reads it's own subset of directives from main.cf config.
# many settings can be dynamically overridden as we move thro the service chain..
# here we override the $myhostname setting depending upon which port we send our 
# outgoing smtp email to.

# custom2  cats service chain 
custom2_cleanup   unix  n       -       -       -       0        cleanup             -o queue_service_name=custom2_qmgr
custom2_qmgr      fifo  n       -       n       300     1        qmgr                -o rewrite_service_name=custom2_rewrite
custom2_rewrite   unix  -       -       n       -       -        trivial-rewrite     -o default_transport=custom2_smtp:
custom2_smtp      unix  -       -       n       -       -        smtp
             -o myhostname=mailer.external.cats.tld
             -o smtp_bind_address=e.f.g.h
             -o smtp_helo_name=cats.tld


# custom1 dogs service chain 
custom1_cleanup   unix  n       -       -       -       0        cleanup             -o queue_service_name=custom1_qmgr
custom1_qmgr      fifo  n       -       n       300     1        qmgr                -o rewrite_service_name=custom1_rewrite
custom1_rewrite   unix  -       -       n       -       -        trivial-rewrite     -o default_transport=custom1_smtp:
custom1_smtp      unix  -       -       n       -       -        smtp
             -o myhostname=mailer.external.dogs.tld
             -o smtp_bind_address=a.b.c.d
             -o smtp_helo_name=dogs.tld


# our main internal entry for the dogs site; all outgoing dogs traffic is
# sent to this (non-standard) port and routed to our custom1 service chain
10026             inet  n      -        n       -       -        smtpd
             -o myhostname=mailer.internal.dogs.tld
             -o cleanup_service_name=custom1_cleanup
           # NB: attempting to override the content_filter directive 
           # *will not work* in postfix < 2.7 since an unspecified nexthop 
           # destination defaults to localhost and causes the email to loop
           # -o content_filter=custom1_smtp:  


# our main internal entry for the cats site; all outgoing cats traffic is
# sent to this (non-standard) port and routed to our custom2 service chain
10027             inet  n      -        n       -       -        smtpd
             -o myhostname=mailer.internal.cats.tld
             -o cleanup_service_name=custom2_cleanup

# yeehar! acu ;)
#


NOTE1: is a caveat:
while directives such as cleanup_service_nameand rewrite_service_name are documented in the configuration parameters, they do not appear to be documented as configurable options parameters for any of the Postfix daemons?!

So at least this seems to be an undocumented approach and hence may well be frowned upon or even possibly deemed as evil in official circles. ~i wouldn't know as i was never able to form a cogent enough question to ever brave the [email protected] official mailing lists!


NOTE2:
there are some folk out there attempting to do this kind of thing in other imaginative ways such as setting up a header_checks FILTER in order overcome the default localhost nexthop destination by dynamically cooking-up a complete transport:recipient-domain-destination:

In /etc/postfix/master.cf:

custom2_smtp      unix  -       -       n       -       -        smtp
             -o myhostname=mailer.external.cats.tld
             -o smtp_bind_address=e.f.g.h
             -o smtp_helo_name=cats.tld

custom2_cleanup   unix  n       -       -       -       0        cleanup 
             -o header_checks=regexp:/etc/postfix/custom2_header_checks

#conditional processing contingent upon entry via some non-standard port
10027             inet  n      -        n       -       -        smtpd
             -o myhostname=mailer.internal.cats.tld
             -o cleanup_service_name=custom2_cleanup


Then in /etc/postfix/custom2_header_checks, pull the recipient domain out of the header-fields with a regex and provide it to the filter directive thus :

/^To:.*@(.*)$/      FILTER    custom2_smtp:$1

While this may seem like a good idea, & partially does work, it is nevertheless certainly a horrid hack; is potentially insecure & at least fails if/when the outgoing email contains multiple recipients. duh!


NOTE3:
if none of the above makes any sense whatsoever, then you probably need to do a bit more rtfming ;)

But seriously, i know there's quite a lot of stuff here.. for various reasons beyond my control, the business is stuck on Postfix 2.3 and i have needed to spend more than 5mins sorting their requirements out; to the extent that my hourly rate has diminished to that of a costa rican pineapple picker (only i do not benefit from their costa' living). so i have tried to lay this all out while it's fresh in my mind and in terms that do not just parrot the official documentation; hopefully so this may help the next poor soul who happens down this particular path ;)

6
  • Yeah not sure what this is about, adding this stuff to my master.cf broke my postfix entirely so the information is either wrong or outdated. Nov 27, 2019 at 20:24
  • @Eight yea, this post is years old &i haven't needed to go near postfix ever since. in this answer i was very clear about the versions i was addressing. maybe you could open your own question; and if you get a resolution; and if it makes sense to; then post a link thro here in another more useful comment. lol
    – violet313
    Mar 5, 2020 at 18:04
  • My comment was referring specifically to the "& above" part of the answer. Which implies major changes were done in 2.7 and that the program still works the same way after. You could try being less cheeky and editing your answer clarifying that :) Especially since this answer has 10k+ views and is highly ranked on Google. Mar 6, 2020 at 14:05
  • 1
    @violet313 It's working great. Thanks for the detailed answer. For Postfix > 2.7, I didn't add the default smtpd ... -o myhostname=mailer.internal.tld entry. Could you tell me what that is for?
    – lucasart
    Sep 12, 2020 at 11:10
  • 1
    @Adriano Lucas myhostname is the internet hostname of your mail system and typically defaults to something like what gethostname returns.. but you can override that default with your own default in master.cf. at least that is my understanding :) ~ rly sry for the late response. there is an annoying rep-whore (h a l f e r) over on SO that *mods his way to stardom.. and has been busy trying to make things difficult for me ever since i cracked a little joke at his expense. so i now don't log in much. &he'll prolly have this comment removed lol..
    – violet313
    Oct 7, 2020 at 23:10
2

After a lot of testing, i must conclude that you cannot do this. It IS possible to dynamically change myhostname, it just doesn't affect the Received header.

With a test having banner use $myhostname, i can see that it changes when i use

-o myhostname=test.test.test

but the received header does not.

I tried using, in main.cf

mydomain=test.test.test
myhostname=$mydomain

This does affect both the Received header and banner. But trying to override the $mydomain

-o mydomain=test.test.test

only affects the banner again.

Thus it seems that the variable used in the Received header is filled from $myhostname before overriding $myhostname from the command line arguments.

1
  • Damn, i have the same conclusion :( Thank you for your time.
    – djaunz
    Aug 27, 2014 at 12:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .