diff --git a/CHANGES b/CHANGES
index 95221d68e7c031d52b40feb7aa9e3765816ff0d5..83e6e26118c1fde41d51b8d785331a463af26c5c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -46,6 +46,8 @@ SIP Changes
    in a multi-channel setup resolved in an individual way.
  * Added 'externtcpport' and 'externtlsport' options to allow custom port
    configuration for the externip and externhost options when tcp or tls is used.
+ * Added support for message body (stored in content variable) to SIP NOTIFY message
+   accessible via AMI and CLI.
 
 IAX2 Changes
 -----------
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 7c619d414fdec9e7af70a25ee493d480727a22bf..27d658a8182ef65eb25571d34a31c35f6eed2a8a 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1640,6 +1640,11 @@ struct sip_refer {
 	enum referstatus status;			/*!< REFER status */
 };
 
+/*! \brief Struct to handle custom SIP notify requests. Dynamically allocated when needed */
+struct sip_notify {
+	struct ast_variable *headers;
+	struct ast_str *content;
+};
 
 /*! \brief Structure that encapsulates all attributes related to running
  *   SIP Session-Timers feature on a per dialog basis.
@@ -1792,7 +1797,7 @@ struct sip_pvt {
 	enum transfermodes allowtransfer;	/*!< REFER: restriction scheme */
 	struct ast_channel *owner;		/*!< Who owns us (if we have an owner) */
 	struct sip_route *route;		/*!< Head of linked list of routing steps (fm Record-Route) */
-	struct ast_variable *notify_headers;    /*!< Custom notify type */
+	struct sip_notify *notify;    /*!< Custom notify type */
 	struct sip_auth *peerauth;		/*!< Realm authentication */
 	int noncecount;				/*!< Nonce-count */
 	unsigned int stalenonce:1;	/*!< Marks the current nonce as responded too */
@@ -2415,7 +2420,6 @@ static int transmit_message_with_text(struct sip_pvt *p, const char *text);
 static int transmit_refer(struct sip_pvt *p, const char *dest);
 static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten);
 static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
-static int transmit_notify_custom(struct sip_pvt *p, struct ast_variable *vars);
 static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader);
 static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
 static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
@@ -2502,6 +2506,7 @@ static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer
 static struct ast_variable *copy_vars(struct ast_variable *src);
 /* static int sip_addrcmp(char *name, struct sockaddr_in *sin);	Support for peer matching */
 static int sip_refer_allocate(struct sip_pvt *p);
+static int sip_notify_allocate(struct sip_pvt *p);
 static void ast_quiet_chan(struct ast_channel *chan);
 static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
 static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
@@ -5610,9 +5615,10 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 	if (p->options)
 		ast_free(p->options);
 
-	if (p->notify_headers) {
-		ast_variables_destroy(p->notify_headers);
-		p->notify_headers = NULL;
+	if (p->notify) {
+		ast_variables_destroy(p->notify->headers);
+		ast_free(p->notify->content);
+		ast_free(p->notify);
 	}
 	if (p->rtp) {
 		ast_rtp_instance_destroy(p->rtp);
@@ -11004,13 +11010,6 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
 	add_header(&req, "Allow", ALLOWED_METHODS);
 	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
 
-	if(p->notify_headers) {
-		char buf[512];
-		for (var = p->notify_headers; var; var = var->next) {
-			ast_copy_string(buf, var->value, sizeof(buf));
-			add_header(&req, var->name, ast_unescape_semicolon(buf));
-		}
-	}
 	if (p->options && p->options->addsipheaders && p->owner) {
 		struct ast_channel *chan = p->owner; /* The owner channel */
 		struct varshead *headp;
@@ -11065,11 +11064,15 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
 			try_suggested_sip_codec(p);
 			add_sdp(&req, p, FALSE, TRUE, FALSE);
 		}
+	} else if (p->notify) {
+		for (var = p->notify->headers; var; var = var->next)
+			add_header(&req, var->name, var->value);
+		add_header_contentLength(&req, ast_str_strlen(p->notify->content));
+		if (ast_str_strlen(p->notify->content))
+			add_line(&req, ast_str_buffer(p->notify->content));
 	} else {
-		if (!p->notify_headers) {
-			add_header_contentLength(&req, 0);
-		}
-	}
+		add_header_contentLength(&req, 0);
+    }
 
 	if (!p->initreq.headers || init > 2)
 		initialize_initreq(p, &req);
@@ -11510,37 +11513,12 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *messa
 	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
 }
 
-/*! \brief Notify device with custom headers from sip_notify.conf */
-static int transmit_notify_custom(struct sip_pvt *p, struct ast_variable *vars) {
-	struct sip_request req;
-	struct ast_variable *var, *newvar;
-
-	initreqprep(&req, p, SIP_NOTIFY);
-
-	/* Copy notify vars and add headers */
-	p->notify_headers = newvar = ast_variable_new("Subscription-State", "terminated", "");
-	add_header(&req, newvar->name, newvar->value);
-	for (var = vars; var; var = var->next) {
-		char buf[512];
-		ast_debug(2, "  Adding pair %s=%s\n", var->name, var->value);
-		ast_copy_string(buf, var->value, sizeof(buf));
-		add_header(&req, var->name, ast_unescape_semicolon(buf));
-		newvar->next = ast_variable_new(var->name, var->value, "");
-		newvar = newvar->next;
-	}
-
-	if (!p->initreq.headers) { /* Initialize first request before sending */
-		initialize_initreq(p, &req);
-	}
-
-	return send_request(p, &req, XMIT_UNRELIABLE, p->ocseq);
-}
-
 static int manager_sipnotify(struct mansession *s, const struct message *m)
 {
 	const char *channame = astman_get_header(m, "Channel");
 	struct ast_variable *vars = astman_get_variables(m);
 	struct sip_pvt *p;
+	struct ast_variable *header, *var;
 
 	if (ast_strlen_zero(channame)) {
 		astman_send_error(s, m, "SIPNotify requires a channel name");
@@ -11567,21 +11545,26 @@ static int manager_sipnotify(struct mansession *s, const struct message *m)
 
 	/* Notify is outgoing call */
 	ast_set_flag(&p->flags[0], SIP_OUTGOING);
+	sip_notify_allocate(p);
+
+	p->notify->headers = header = ast_variable_new("Subscription-State", "terminated", "");
+
+	for (var = vars; var; var = var->next) {
+		if (!strcasecmp(var->name, "Content")) {
+			if (ast_str_strlen(p->notify->content))
+				ast_str_append(&p->notify->content, 0, "\r\n");
+			ast_str_append(&p->notify->content, 0, "%s", var->value);
+		} else {
+			header->next = ast_variable_new(var->name, var->value, "");
+			header = header->next;
+		}
+	}
 
-	/* Recalculate our side, and recalculate Call ID */
-	ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
-	build_via(p);
-	ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
-	build_callid_pvt(p);
-	ao2_t_link(dialogs, p, "Linking in new name");
 	dialog_ref(p, "bump the count of p, which transmit_sip_request will decrement.");
 	sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
+	transmit_invite(p, SIP_NOTIFY, 0, 2);
 
-	if (!transmit_notify_custom(p, vars)) {
-		astman_send_ack(s, m, "Notify Sent");
-	} else {
-		astman_send_error(s, m, "Unable to send notify");
-	}
+	astman_send_ack(s, m, "Notify Sent");
 	ast_variables_destroy(vars);
 	return 0;
 }
@@ -12024,6 +12007,15 @@ static int sip_refer_allocate(struct sip_pvt *p)
 	return p->refer ? 1 : 0;
 }
 
+/*! \brief Allocate SIP refer structure */
+static int sip_notify_allocate(struct sip_pvt *p)
+{
+	p->notify = ast_calloc(1, sizeof(struct sip_notify));
+	if (p->notify)
+		p->notify->content = ast_str_create(128);
+	return p->notify ? 1 : 0;
+}
+
 /*! \brief Transmit SIP REFER message (initiated by the transfer() dialplan application
 	\note this is currently broken as we have no way of telling the dialplan
 	engine whether a transfer succeeds or fails.
@@ -17199,6 +17191,8 @@ static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 
 	for (i = 3; i < a->argc; i++) {
 		struct sip_pvt *p;
+		char buf[512];
+		struct ast_variable *header, *var;
 
 		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
 			ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
@@ -17216,17 +17210,28 @@ static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 
 		/* Notify is outgoing call */
 		ast_set_flag(&p->flags[0], SIP_OUTGOING);
+		sip_notify_allocate(p);
+		p->notify->headers = header = ast_variable_new("Subscription-State", "terminated", "");
+
+		for (var = varlist; var; var = var->next) {
+			ast_copy_string(buf, var->value, sizeof(buf));
+			ast_unescape_semicolon(buf);
+
+			if (!strcasecmp(var->name, "Content")) {
+				if (ast_str_strlen(p->notify->content))
+					ast_str_append(&p->notify->content, 0, "\r\n");
+				ast_str_append(&p->notify->content, 0, "%s", buf);
+			} else {
+				header->next = ast_variable_new(var->name, buf, "");
+				header = header->next;
+			}
+		}
 
 		/* Recalculate our side, and recalculate Call ID */
-		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
-		build_via(p);
-		ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
-		build_callid_pvt(p);
-		ao2_t_link(dialogs, p, "Linking in new name");
 		ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n", a->argv[2], a->argv[i]);
 		dialog_ref(p, "bump the count of p, which transmit_sip_request will decrement.");
 		sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
-		transmit_notify_custom(p, varlist);
+		transmit_invite(p, SIP_NOTIFY, 0, 2);
 	}
 
 	return CLI_SUCCESS;
@@ -18397,7 +18402,7 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest
 		break;
 	case 401:   /* Not www-authorized on SIP method */
 	case 407:   /* Proxy auth */
-		if (!p->notify_headers) {
+		if (!p->notify) {
 			break; /* Only device notify can use NOTIFY auth */
 		}
 		ast_string_field_set(p, theirtag, NULL);
diff --git a/configs/sip_notify.conf.sample b/configs/sip_notify.conf.sample
index 74ee9554b24b6cb424c2693759349c994f008f8a..145bf7dbe67bdc9077d31e3899caf4168c9a6235 100644
--- a/configs/sip_notify.conf.sample
+++ b/configs/sip_notify.conf.sample
@@ -1,53 +1,50 @@
+; rfc3842
+
+[clear-mwi]
+Event=>message-summary
+Content-type=>application/simple-message-summary
+Content=>Messages-Waiting: no
+Content=>Message-Account: sip:asterisk@127.0.0.1
+Content=>Voice-Message: 0/0 (0/0)
+
 ; Aastra
 
 [aastra-check-cfg]
 Event=>check-sync
-Content-Length=>0
 
 [aastra-xml]
 Event=>aastra-xml
-Content-Length=>0
 
 ; Linksys
 
 [linksys-cold-restart]
 Event=>reboot_now
-Content-Length=>0
 
 [linksys-warm-restart]
 Event=>restart_now
-Content-Length=>0
 
 ; Polycom
 
 [polycom-check-cfg]
 Event=>check-sync
-Content-Length=>0
 
 ; Sipura
 
 [sipura-check-cfg]
 Event=>resync
-Content-Length=>0
 
 [sipura-get-report]
 Event=>report
-Content-Length=>0
 
 ; snom
 
 [snom-check-cfg]
 Event=>check-sync\;reboot=false
-Content-Length=>0
 
 [snom-reboot]
 Event=>reboot
-Content-Length=>0
 
-;;
-;; The following NOTIFY messages are not confirmed to work.
-;;
+; Cisco
 
 [cisco-check-cfg]
 Event=>check-sync
-Content-Length=>0