First Axiom of Communication
"You cannot not communicate. Every behavior is a kind of communication. Because behavior does not have a counterpart (there is no anti-behavior), it is not possible not to communicate."
- Paul Watzlawick
"You cannot not communicate. Every behavior is a kind of communication. Because behavior does not have a counterpart (there is no anti-behavior), it is not possible not to communicate."
- Paul Watzlawick
"Every non-deterministic finite state machine has a corresponding deterministic finite state machine that accepts exactly the same strings."
CTRL-N/CTRL-P
I had the exact same reaction as this kid...
Python shows an unexpected behavior in situations where a local variable is defined with the same name as a global variable. Here's an example:
x = 2
def foo():
print x
x = 5
You'd probably expect foo() to print "2" (the value of the global variable 'x'). Instead it throws an error:
UnboundLocalError: local variable 'x' referenced before assignment
The reason for the error is that we're defining a local variable 'x' later in the function. But why would a variable declaration later in the code have any effect?
To get an intuition for what's happening in Python, it's helpful to look at variable hoisting behavior in JavaScript. Here's the parallel code:
var x = 2;
function foo(){
console.log(x);
var x = 5;
}
You'd probably expect foo() to print "2" but instead it prints the JavaScript keyword undefined. Undefined translates as "the variable x has been declared, but has not yet been initialized with a value". This is essentially the same as the Python error, except that in JavaScript undefined is a perfectly legal value.
Here's what's happening. The Javascript interpreter reads the entire function and finds the variable definition. It then moves ("hoists") the variable declaration to the top of the function, while leaving the variable initialization in its original position. So when the function is executed, it's as if the code had been written like this:
var x = 2;
function foo(){
var x; // the hoisted variable declaration
console.log(x);
x = 5;
}
Now it's easy to see that the local variable x already exists when 'x' is referenced in the console.log() function. That explains why the value of the global x isn't printed. And since the local x has not yet been assigned a value when console.log() is called, its value is undefined.
This is the same situation we're seeing in the Python example. The interpreter is aware that a local variable x exists, but it is complaining because x has not yet been assigned a value. The situation is harder to understand in Python, however, because Python lacks the ability to declare variables without assigning them values. Thus while Python's internals are different than JavaScript's, understanding JavaScript variable hoisting may help make Python's behavior a little less mystifying.
Postfix is the default mailserver on CentOS. The following tutorial will set up email forwarding for the domains on our server. We will assume that the primary domain on the server is called host.com.
1. Create an A record for the mailserver, e.g.
mail.host.com
2. Add an MX record to any hosted domains (e.g. mydomain1.com) pointing to mail.host.com with priority 10.
3. Use dig to check the settings (look at ANSWER SECTION)
$ dig mail.host.com @dns1.stabletransit.com
$ dig mydomain1.com mx @dns1.stabletransit.com
Next, use the GUI to open the SMTP port (port 25) so we can receive connections:
$ sudo system-config-firewall-tui
# open the port for SMTP
$ sudo service iptables restart
We can check the settings:
$ sudo iptables -L
# output should contain the line:
# ACCEPT tcp -- anywhere anywhere tcp dpt:smtp
Start Postfix:
$ sudo service postfix start
$ sudo chkconfig postfix on
Open the Postfix config file main.cf:
$ sudo vim /etc/postfix/main.cf
Uncomment or add the following lines:
inet_interfaces = all
relay_domains =
mynetworks = 192.168.0.0/24, 127.0.0.0/8
myhostname = mail.host.com
Finally, add virtual_alias_domains, which is a list of your hosted domains. And add virtual_alias_maps, which is a file that will hold the forwarder-to-address mappings. I'd like a better way to handle this, like we did with mass virtual hosts in httpd.conf, but I haven't had time to figure one out yet:
virtual_alias_domains = mydomain1.com, mydomain2.com
virtual_alias_maps = hash:/etc/postfix/virtual
Then open the virtual file:
$ sudo vim /etc/postfix/virtual
And add each email forwarder:
me@mydomain1.com me@gmail.com
someone@mydomain2.com wherever@yahoo.com
# optionally, add a catch-all address for the domain
@mydomain1.com another@outlook.com
The virtual file could also be built from a database if that suits you needs better.
Finally, reload postfix settings:
# rebuild the forwarder database
$ sudo postmap /etc/postfix/virtual
# restart postfix
$ sudo service postfix restart
Make sure we can connect on port 25:
$ telnet mail.host.com 25
220 mail.host.com ESMTP Postfix
# Press CTRL + ]
telnet > quit
The email forwarders we created in the virtual file should be working now. Note that the DNS settings at the beginning of the tutorial will take efect in about 5 minutes if your DNS is hosted at Rackspace. Some other DNS providers can take up to 48 hours.
One problem with forwarding mail is that your server's IP address reputation will be harmed by forwarding spam messages. Gmail recommends tagging spam using SpamAssassin.