diff --git a/interface/lib/classes/tools_monitor.inc.php b/interface/lib/classes/tools_monitor.inc.php
index d57b9b7a3f425a291c842ef089183aea1f59a3f4..7a5efea27989c9c05746a408d329c7a363b4d50a 100644
--- a/interface/lib/classes/tools_monitor.inc.php
+++ b/interface/lib/classes/tools_monitor.inc.php
@@ -576,6 +576,25 @@ class tools_monitor {
 		return $html;
 	}
 
+	function showMx_ip_match() {
+		global $app;
+
+		/* fetch the Data from the DB */
+		$record = $app->db->queryOneRecord("SELECT data, state FROM monitor_data WHERE type = 'mx_ip_match' and server_id = ? ORDER BY created DESC", $_SESSION['monitor']['server_id']);
+
+		if(isset($record['data'])) {
+			$data = unserialize($record['data']);
+			$html = '';
+			foreach ($data as $domain => $text) {
+				$html .= "$domain: $text<br />";
+			}
+		} else {
+			$html = '<p>'.$app->lng("no_data_mx_ip_match_txt").'</p>';
+		}
+
+		return $html;
+	}
+
 	function getDataTime($type) {
 		global $app;
 
diff --git a/interface/web/monitor/lib/lang/en.lng b/interface/web/monitor/lib/lang/en.lng
index c790ed1d763b36452700fb203a175ec3ead3b337..eec736c5488066302d037187151c289619ce6d28 100644
--- a/interface/web/monitor/lib/lang/en.lng
+++ b/interface/web/monitor/lib/lang/en.lng
@@ -166,4 +166,7 @@ $wb['no_munin_url_defined_txt'] = 'No Munin URL defined.';
 $wb['no_permissions_to_view_munin_txt'] = 'You are not allowed to access Munin.';
 $wb['Database size'] = 'Database size';
 $wb['MySQL Database size'] = 'MySQL Database size';
+$wb['monitor_title_mx_ip_match_txt'] = 'MX record to server IP match';
+$wb['no_data_mx_ip_match_txt'] = 'MX record check data present';
+$wb['monitor_serverstate_mx_ip_matchwarning_txt'] = 'Not all DNS MX records match the server IP';
 ?>
diff --git a/interface/web/monitor/show_data.php b/interface/web/monitor/show_data.php
index 80f246ee2dcec04b6a255c1c5d9bec58adbd5420..13258398413030a45ee9633ad89fa1510fe87fea 100644
--- a/interface/web/monitor/show_data.php
+++ b/interface/web/monitor/show_data.php
@@ -114,6 +114,14 @@ case 'mailq':
 	$description = '';
 	$add_padding = true;
 	break;
+case 'mx_ip_match':
+	$template = 'templates/show_data.htm';
+	$output .= $app->tools_monitor->showMx_ip_match();
+	$time = $app->tools_monitor->getDataTime('mx_ip_match');
+	$title = $app->lng("monitor_title_mx_ip_match_txt"). ' ('. $monTransSrv .' : ' . $_SESSION['monitor']['server_name'] . ')';
+	$description = '';
+	$add_padding = true;
+	break;
 case 'raid_state':
 	$template = 'templates/show_data.htm';
 	$output .= $app->tools_monitor->showRaidState();
diff --git a/interface/web/monitor/show_sys_state.php b/interface/web/monitor/show_sys_state.php
index 9e70496a81927067e59eed5f60909d4f5fe709c3..fdfc47e25363cf5b52164f2eb75b44a5b411c037 100644
--- a/interface/web/monitor/show_sys_state.php
+++ b/interface/web/monitor/show_sys_state.php
@@ -557,6 +557,22 @@ function _processDbState($type, $serverId, $serverState, $messages) {
 			break;
 		}
 	}
+	if ($type == 'mx_ip_match') {
+		switch ($record['state']) {
+		case 'ok':
+			$messages[$app->lng("monitor_serverstate_listok_txt")][] = $app->lng("monitor_serverstate_mx_ip_matchok_txt") . ' ' .
+				"<a href='#' data-load-content='monitor/show_data.php?type=mx_ip_match'>[" . $app->lng("monitor_serverstate_more_txt") . "]</a>";
+			break;
+		case 'warning':
+			$messages[$app->lng("monitor_serverstate_listwarning_txt")][] = $app->lng("monitor_serverstate_mx_ip_matchwarning_txt") . ' ' .
+				"<a href='#' data-load-content='monitor/show_data.php?type=mx_ip_match'>[" . $app->lng("monitor_serverstate_more_txt") . "]</a>";
+			break;
+		default:
+			$messages[$app->lng("monitor_serverstate_listunknown_txt")][] = $app->lng("monitor_serverstate_mx_ip_match_unknown_txt") . ' ' .
+				"<a href='#' data-load-content='monitor/show_data.php?type=mx_ip_match'>[" . $app->lng("monitor_serverstate_more_txt") . "]</a>";
+			break;
+		}
+	}
 
 	if ($type == 'sys_log') {
 		switch ($record['state']) {
diff --git a/server/lib/classes/cron.d/100-monitor_domain_mx.php b/server/lib/classes/cron.d/100-monitor_domain_mx.php
new file mode 100755
index 0000000000000000000000000000000000000000..fe1494ddb5fc32ee251193c84d6daeec1485def8
--- /dev/null
+++ b/server/lib/classes/cron.d/100-monitor_domain_mx.php
@@ -0,0 +1,138 @@
+<?php
+
+/*
+Copyright (c) 2020, Herman van Rink, Initfour websolutions
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+class cronjob_monitor_domain_mx  extends cronjob {
+
+	// job schedule
+	protected $_schedule = '* 6 * * *';
+	protected $_run_at_new = true;
+
+	private $_tools = null;
+
+	/* this function is optional if it contains no custom code */
+	public function onPrepare() {
+		global $app;
+
+		parent::onPrepare();
+	}
+
+	/* this function is optional if it contains no custom code */
+	public function onBeforeRun() {
+		global $app;
+
+		return parent::onBeforeRun();
+	}
+
+	public function onRunJob() {
+		global $app, $conf;
+
+		$app->uses('getconf,functions');
+		$mail_config = $app->getconf->get_server_config($conf['server_id'], 'server');
+
+		/* used for all monitor cronjobs */
+		$app->load('monitor_tools');
+		$this->_tools = new monitor_tools();
+		/* end global section for monitor cronjobs */
+
+
+		// Initialize data array
+		$data = array();
+
+		// the id of the server as int
+		$server_id = intval($conf['server_id']);
+
+		$smtpin_ips = gethostbynamel($mail_config['hostname']);
+		$smtpin_ips_v6 = $app->functions->gethostbynamel6($mail_config['hostname']);
+		if ($smtpin_ips_v6) {
+			$smtpin_ips = array_merge($smtpin_ips, $smtpin_ips_v6);
+		}
+		$maildomains = $app->db->queryAllRecords("SELECT domain, active FROM mail_domain WHERE server_id = ?", $server_id);
+		if(is_array($maildomains)) {
+			foreach ($maildomains as $maildomain) {
+				$mx = array();
+				$found_mx = getmxrr($maildomain['domain'], $mx);
+
+				$app->log('mx re:' . print_r($mx, 1));
+
+				$first_mx = array_shift($mx);
+				$mx_ip = gethostbyname($first_mx);
+
+				if (!in_array( $mx_ip, $smtpin_ips)) {
+					if ($maildomain['active'] == 'y') {
+						$app->log('Mail domain[' . $maildomain['domain'] . '] is active but the DNS does not match our IP.', LOGLEVEL_WARN);
+						$state = 'warning';
+						$data[$maildomain['domain']] = 'Domain is active but the DNS does not match our IP.';
+					} else {
+
+						$app->log('Good, the mail domain[' . $maildomain['domain'] . '] is not active and DNS is not pointing to us.', LOGLEVEL_DEBUG);
+					}
+				}
+				else {
+					if ($maildomain['active'] == 'n') {
+						$app->log('DNS points to our IP but the mail domain[' . $maildomain['domain'] . '] is not active.', LOGLEVEL_WARN);
+						$state = 'warning';
+						$data[$maildomain['domain']] = 'DNS points to our IP but the mail domain is not active.';
+					}
+					else {
+						// DNS OK.
+					}
+				}
+			}
+		}
+
+		$res = array();
+		$res['server_id'] = $server_id;
+		$res['type'] = 'mx_ip_match';
+		$res['data'] = $data;
+		$res['state'] = $state;
+
+		/**
+		 * Insert the data into the database
+		 */
+		$sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' .
+			'VALUES (?, ?, UNIX_TIMESTAMP(), ?, ?)';
+		$app->dbmaster->query($sql, $res['server_id'], $res['type'], serialize($res['data']), $res['state']);
+
+		// The new data is written, now we can delete the old one.
+		$this->_tools->delOldRecords($res['type'], $res['server_id']);
+
+		parent::onRunJob();
+	}
+
+	/* this function is optional if it contains no custom code */
+	public function onAfterRun() {
+		global $app;
+
+		parent::onAfterRun();
+	}
+
+}
+
+?>
diff --git a/server/lib/classes/functions.inc.php b/server/lib/classes/functions.inc.php
index 5296c3012b65cb4bf0d9889c893252e99ec9d4a8..7cd5a62da50eda0777e973a16ffc4699df11b12b 100644
--- a/server/lib/classes/functions.inc.php
+++ b/server/lib/classes/functions.inc.php
@@ -481,6 +481,63 @@ class functions {
 		}
 	}
 
+	/**
+	 *	From https://www.php.net/manual/en/function.gethostbyname.php#70936
+	 */
+	public function gethostbyname6($host, $try_a = false) {
+		// get AAAA record for $host
+		// if $try_a is true, if AAAA fails, it tries for A
+		// the first match found is returned
+		// otherwise returns false
+
+		$dns = gethostbynamel6($host, $try_a);
+		if ($dns == false) { return false; }
+		else { return $dns[0]; }
+	}
+
+	/**
+	 *	From https://www.php.net/manual/en/function.gethostbyname.php#70936
+	 */
+	public function gethostbynamel6($host, $try_a = false) {
+		// get AAAA records for $host,
+		// if $try_a is true, if AAAA fails, it tries for A
+		// results are returned in an array of ips found matching type
+		// otherwise returns false
+
+		$dns6 = dns_get_record($host, DNS_AAAA);
+		if ($try_a == true) {
+			$dns4 = dns_get_record($host, DNS_A);
+			$dns = array_merge($dns4, $dns6);
+		}
+		else { $dns = $dns6; }
+		$ip6 = array();
+		$ip4 = array();
+		foreach ($dns as $record) {
+			if ($record["type"] == "A") {
+				$ip4[] = $record["ip"];
+			}
+			if ($record["type"] == "AAAA") {
+				$ip6[] = $record["ipv6"];
+			}
+		}
+		if (count($ip6) < 1) {
+			if ($try_a == true) {
+				if (count($ip4) < 1) {
+					return false;
+				}
+				else {
+					return $ip4;
+				}
+			}
+			else {
+				return false;
+			}
+		}
+		else {
+			return $ip6;
+		}
+	}
+
 }
 
 ?>