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?

[Webinar] Streamline your web hosting managementRegister Today

bevhostConnect With a Mentor 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?

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
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/
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

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.
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.
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.
All Courses

From novice to tech pro — start learning today.