You can also look at roles as a way of separating tasks depending on the different roles roles. This way you can have separate variables for each of one of your roles. For example you may have a url variable for apache1 and a separate url variable for the role apache2.
NOTE: Using set_fact as described below sets a fact/variable onto the remote servers that the task is running against. This fact/variable will then persist across subsequent tasks for the entire duration of your playbook.
Also, these facts are immutable (for the duration of the playbook), and cannot be changed once set.
ORIGINAL ANSWER
Use set_fact before your task to set facts which seem interchangeable with variables:
Whenever you have a module followed by a variable on the same line in ansible the parser will treat the reference variable as the beginning of an in-line dictionary. For example:
- name: some example
command: \{\{ myapp }} -a foo
The default here is to parse the first part of \{\{ myapp }} -a foo as a dictionary instead of a string and you will get an error.
So you must quote the argument like so:
- name: some example
command: "\{\{ myapp }} -a foo"
In Your example, apache.yml is tasklist, but not playbook
In depends on desired architecture, You can do one of:
Convert apache.yml to role. Then define tasks in roles/apache/tasks/mail.yml and variables in roles/apache/defaults/mail.yml (vars in defaults can be overriden when role applied)