I'd like to get an email sent whenever one of the hosts in ansible cannot be reached through SSH.

I've tried to write a playbook to do this (see below). After gathering facts, any unreachable host is discarded, so my task sending the email is never executed for the unreachable hosts.

-name: Check host accessibility
  hosts: all
    - local_action: shell ssh deploy@{{ansible_hostname}} echo OK
      register: check_ssh
    - local_action: debug msg="{{check_ssh.stdout}}"
      when: check_ssh.stdout != "OK"

Thanks a lot.

2 Answers 2


Here is my solution for ansible > 2.0 :

- name: Check host accessibility
  hosts: all
  user: deploy
  gather_facts: no
    - block:
        - command: echo OK

        - assert:
              - ansible_play_hosts == ansible_play_hosts_all

        - name: send email when something goes wrong (pe, cannot reach a machine)
            module: mail
            host: localhost
            to: < email here >
            from: < email here >
            subject: 'Host check - {{ (ansible_play_hosts_all | difference(ansible_play_hosts)) | first }}'
            body: 'Cannot login into the machine'
          when: inventory_hostname == "< hostname of main server here >"

That's the best solution I've been able to produce so far. It's a pitty that ansible doesn't consider unreachable hosts as to be failed, so a rescue section is never called. I've overcomed that issue counting the number of host that executed the last task vs the total amount of hosts. If it's different it means that at least one host is unreachable, thus executing the assert and going to the rescue section. Then, the second problem is that the assert applies to all hosts, so we have to pick only one host to send the email (in this case I picked the server where ansible is installed).


I've found that using a Python script is the easiest solution (easier than a callback plugin, at least on my ansible version 1.7):

#!/usr/bin/env python

from __future__ import print_function
import ansible.inventory
import ansible.runner                                                                                   
from subprocess import Popen, PIPE
import sys

TO = "root"

def message(subject, body):
    p = Popen(["mail", "-s", subject, TO], stdin=PIPE)                                                  
    res = p.wait()                                                                                      
    if res != 0:
        print("Failed to send message", file=sys.stderr)                                                

def main():
    im = ansible.inventory.Inventory()                                                                  
    runner = ansible.runner.Runner(                                                                     
        module_args='sh -c "echo OK"',                                                                  
    run = runner.run()
    nosudo = set(run["dark"].keys())

    runner = ansible.runner.Runner(
        module_args='sh -c "echo OK"',                                                                  
    run = runner.run()                                                                                  
    nonet = set(run["dark"].keys()) 

    nosudo = nosudo - nonet

    for host in nosudo:                                                                                 
        message("Host check: %s" % host,
                "Cannot execute 'sudo -u root ...' as user 'deploy'.")                                  
    for host in nonet:
        message("Host check: %s" % host,
                "Cannot login into the machine.")

if __name__ == '__main__':                                                                              
  • Unfortunately the Python API has changed in ansible >2.0 and this method is no longer valid. (ansible.runner is deprecated and no loger available in v2.4)
    – Hopobcn
    Jan 29, 2018 at 14:07
  • Is there a new alternative? Jan 30, 2018 at 16:31

You must log in to answer this question.

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