Restricting Senders in Postfix

I'm using Postfix 2.2 with a MySQL backend.  I would like to be able to restrict certain senders to only be able to send to certain domains.   I've done a lot of reading about this and done a lot of trial and error, but I'm using a production email server to figure this out, so my trial and error is limited.  Basically what I've learned is that I need to use smtpd_recipient_restrictions and use restriction classes. Ok, so I've somewhat tried that, but I can't seem to get it right.  When I add the mysql lookup query for check_sender_access it doesn't seem to be working.

Here's my postconf -n
alias_maps = hash:/etc/aliases
broken_sasl_auth_clients = yes
command_directory = /usr/sbin
config_directory = /etc/postfix
content_filter = smtp-amavis:[]:10024
daemon_directory = /usr/libexec/postfix
debug_peer_level = 2
html_directory = no
inet_interfaces = all
mail_owner = postfix
mailbox_size_limit = 0
mailq_path = /usr/bin/mailq.postfix
manpage_directory = /usr/share/man
maximal_backoff_time = 600s
maximal_queue_lifetime = 1d
message_size_limit = 0
milter_default_action = accept
milter_macro_daemon_name = ORIGINATING
milter_protocol = 2
minimal_backoff_time = 300s
mydestination = $myhostname, localhost.$mydomain, localhost,
mydomain =
myhostname =
mynetworks = my.ip.addresses
newaliases_path = /usr/bin/newaliases.postfix
non_smtpd_milters = inet:
queue_directory = /var/spool/postfix
queue_run_delay = 300s
readme_directory = /usr/share/doc/postfix-2.3.3/README_FILES
sample_directory = /usr/share/doc/postfix-2.3.3/samples
sendmail_path = /usr/sbin/sendmail.postfix
setgid_group = postdrop
show_user_unknown_table_name = no
smtpd_data_restrictions = reject_unauth_pipelining, permit
smtpd_delay_reject = yes
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks, check_helo_access hash:/etc/postfix/helo_access, reject_invalid_hostname,reject_non_fqdn_hostname, permit
smtpd_milters = inet:
smtpd_recipient_restrictions = permit_mynetworks, reject_invalid_hostname,  reject_non_fqdn_hostname,  reject_non_fqdn_sender, reject_non_fqdn_recipient,  reject_unknown_sender_domain,  mysql:/etc/postfix/, reject_unauth_destination, permit_sasl_authenticated, check_policy_service inet:, permit
smtpd_restriction_classes = gcmm_only
smtpd_sasl_auth_enable = yes
smtpd_sasl_exceptions_networks = $mynetworks
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
smtpd_sasl_type = dovecot
smtpd_sender_restrictions = reject_non_fqdn_sender, reject_unknown_sender_domain, permit_sasl_authenticated,  permit_mynetworks,  permit
smtpd_tls_cert_file = /etc/ssl/
smtpd_tls_key_file = /etc/ssl/
smtpd_tls_loglevel = 0
smtpd_tls_received_header = no
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:/var/spool/postfix/smtpd_tls_session_cache
tls_random_source = dev:/dev/urandom
unknown_local_recipient_reject_code = 550
virtual_alias_maps = hash:/etc/postfix/virtual_aliases, mysql:/etc/postfix/
virtual_gid_maps = static:1001
virtual_mailbox_base = /vmail
virtual_mailbox_domains = mysql:/etc/postfix/
virtual_mailbox_limit = 0
virtual_mailbox_maps = mysql:/etc/postfix/
virtual_minimum_uid = 1001
virtual_transport = dovecot
virtual_uid_maps = static:1001
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

I have used to use that configuration:

If the aim is : and user shall only be able to send email to and subdomains.

1- /etc/postfix/restricted_senders: reject_unauth_destination reject_unauth_destination


labris_postmap /etc/postfix/restricted_senders

3- /etc/postfix/ ...

smtpd_sender_restrictions =
 check_sender_access hash:/etc/postfix/restricted_senders,

We define restricted_senders as sender control point. Then you can define some policy to that certain sender which is defined by restricted_Senders file. These policies can be found in

After this configuration user1 and user2 can only send email to your internal domain.

Also, I have not tried but please try that configuration:

Add check_recipient_access hash:/etc/postfix/allowed_domains check_recipient_access hash:/etc/postfix/allowed_domains

and add your allowed domains into the file allowed_domains

Do not forget postmap each text file.

I assume that the table pointed to by has the result gcmm_only for the users who are going to have restricted access.

However, I don't see anywhere that you have specified what gcmm_only means. I would expect to see something like this

gcmm_only = check_recipient_access mysql:/etc/postfix/
asaivanAuthor Commented:

Here's the thing, I'm trying to get the gcmm_only = check_recipient_access to be a look up for some column in my MySQL table.  I'm experienced with MySQL, and I know how to write queries of varying difficulty, but I don't really understand exactly how to write the correct query for Postfix, or perhaps there's something in the order of the configuration parameters which I'm setting incorrectly, or whatever. I have:

user = user
password = password
hosts = xx.xx.xx.xx
dbname = postfix
table = mailbox
select_field = smtpaccess
where_field = username

The field smtpaccess has the restriction classes listed, gcmm_only, or unrestricted for that particular user.

Then for the restriction classes I have
unrestricted = permit
gcmm_only = check_restricted_senders:/etc/postfix/, restrict was set up as follows:
user = user
password = password
hosts = xx.xx.xx.xx
dbname = postfix
table = mailbox
select_field = domain
where_field = domain

This, in theory, is supposed to return the list of all the local domains which are able to be accessed...

However, it's not working.  I can see that I'm doing something wrong, but I can't see what it is.
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

There is no check called "check_restricted_senders"
You might find this syntax easier for postfix 2.2 and greater.
user = someone
password = some_password
dbname = customer_database
query = SELECT forw_addr FROM mxaliases WHERE alias='%s' AND status='paid'

Open in new window

Basically without restriction classes, postfix can only check one thing at a time either sender access , client access or recepient access etc.
You have a situation where you want to check two things at once.

So, you create a class to do the second half of the restriction and use it a a result in the first restrictions.

check senders
  sender 1  dunno
  sender 2  permit
  sender 3  my_check

my_check = check recips

check recips
  recip 1  dunno
  recip 2  permit
asaivanAuthor Commented:
>>There is no check called "check_restricted_senders"

Should have been check_recipient_access...
Did you get it working?  If not what part are you stuck on?
asaivanAuthor Commented:
Can you explain some of the special characters such as %s?  I know there are several, it would help me wrap my mind around this.
asaivanAuthor Commented:
Also I have smtpd_recipient_restrictions = permit_mynetworks as the first item in the list.  Could this be overriding my check_sender_access which is later on?

> Can you explain some of the special characters such as %s?

When you do a lookup in a database you have a lookup key which returns a value if found in the database.

%s is a C programming language construct which means "insert string here"
%d insert decimal here
%0.4f insert floating point number with 4 decimal places here

postfix only uses %s.

So if used in a..
check_client_access, %s will be the client IP address or PTR address.
check_sender_access, %s will be the sender email address or domain name,
check_recipient_access, %s will be the recipient email address or domain name.
> Also I have smtpd_recipient_restrictions = permit_mynetworks as the first item in the list.
> Could this be overriding my check_sender_access which is later on?

If the first entry is permit_mynetworks, then any client connection from a machine inside mynetworks will receive a permit and no more rules will be processed.

Basically postifx goes through the rules until it finds a decisive action.
eg permit or reject or "550 go away spammer"

It is possible to have other indecisive responses in an access list
eg dunno, defer_if_permit

dunno means stop processing more rules in this list and move onto the net item

/etc/postfix/sender_access      dunno               550 Only Bob is allowed to send mail from

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
asaivanAuthor Commented:
OK, that helps.  I changed it around to be:
smtpd_recipient_restrictions = check_sender_access mysql:/etc/postfix/

as the first item, and it works, for outgoing mail, now, if I want to block incoming mail, should I add check_recipient_access there as well?
Sure can, add any number of restrictions in the order you want them to be applied.
asaivanAuthor Commented:
Thanks for the help.  It really helps to have someone explain things in a certain way.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Email Servers

From novice to tech pro — start learning today.