diff --git a/configs/pjsip.conf.sample b/configs/pjsip.conf.sample
index cd6deae5bef3db7ca2e115fe9c127a5ac5845bc4..5eb5335dae531e262ef492eed374fe444b97682f 100644
--- a/configs/pjsip.conf.sample
+++ b/configs/pjsip.conf.sample
@@ -603,8 +603,9 @@
 ;user_agent=     ; Value used in User Agent header for SIP requests and Server
                  ; header for SIP responses (default: Populated by Asterisk
                  ; Version)
-
-
+;default_outbound_endpoint= ; Endpoint to use when sending an outbound request
+                            ; to a URI without a specified endpoint.
+                            ; (default: "default_outbound_endpoint")
 
 
 ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index d34005d621dc38c835c3fbfa2418fcd1c534bda5..18d1aafff29c66d28a8615ee49baebed7b44576d 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -1368,6 +1368,13 @@ struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata);
  */
 struct ao2_container *ast_sip_get_endpoints(void);
 
+/*!
+ * \brief Retrieve the default outbound endpoint.
+ *
+ * \retval The default outbound endpoint, NULL if not found.
+ */
+struct ast_sip_endpoint *ast_sip_default_outbound_endpoint(void);
+
 /*!
  * \brief Retrieve relevant SIP auth structures from sorcery
  *
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 52a949257567076d1232231b522d91d19af43d28..08c4552429dcce684feeb23871c2ea55925e6b1c 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -1025,6 +1025,10 @@
 				<configOption name="user_agent" default="Asterisk &lt;Asterisk Version&gt;">
 					<synopsis>Value used in User-Agent header for SIP requests and Server header for SIP responses.</synopsis>
 				</configOption>
+				<configOption name="default_outbound_endpoint" default="default_outbound_endpoint">
+					<synopsis>Endpoint to use when sending an outbound request to a URI without a specified endpoint.</synopsis>
+				</configOption>
+
 			</configObject>
 		</configFile>
 	</configInfo>
diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c
index d883e5d4724c4bb173403324462f7b7b0395b2fb..1ae3e15771216d92c6c410b8e6440519435fd169 100644
--- a/res/res_pjsip/config_global.c
+++ b/res/res_pjsip/config_global.c
@@ -22,11 +22,13 @@
 #include <pjlib.h>
 
 #include "asterisk/res_pjsip.h"
+#include "include/res_pjsip_private.h"
 #include "asterisk/sorcery.h"
 #include "asterisk/ast_version.h"
 
 #define DEFAULT_MAX_FORWARDS 70
 #define DEFAULT_USERAGENT_PREFIX "Asterisk PBX"
+#define DEFAULT_OUTBOUND_ENDPOINT "default_outbound_endpoint"
 
 static char default_useragent[128];
 
@@ -34,6 +36,7 @@ struct global_config {
 	SORCERY_OBJECT(details);
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(useragent);
+		AST_STRING_FIELD(default_outbound_endpoint);
 	);
 	/* Value to put in Max-Forwards header */
 	unsigned int max_forwards;
@@ -70,6 +73,30 @@ static int global_apply(const struct ast_sorcery *sorcery, void *obj)
 	return 0;
 }
 
+static struct global_config *get_global_cfg(void)
+{
+	RAII_VAR(struct ao2_container *, globals, ast_sorcery_retrieve_by_fields(
+			 ast_sip_get_sorcery(), "global", AST_RETRIEVE_FLAG_MULTIPLE,
+			 NULL), ao2_cleanup);
+
+	if (!globals) {
+		return NULL;
+	}
+
+	return ao2_find(globals, NULL, 0);
+}
+
+char *ast_sip_global_default_outbound_endpoint(void)
+{
+	RAII_VAR(struct global_config *, cfg, get_global_cfg(), ao2_cleanup);
+
+	if (!cfg) {
+		return NULL;
+	}
+
+	return ast_strdup(cfg->default_outbound_endpoint);
+}
+
 int ast_sip_initialize_sorcery_global(struct ast_sorcery *sorcery)
 {
 	snprintf(default_useragent, sizeof(default_useragent), "%s %s", DEFAULT_USERAGENT_PREFIX, ast_get_version());
@@ -85,6 +112,8 @@ int ast_sip_initialize_sorcery_global(struct ast_sorcery *sorcery)
 			OPT_UINT_T, 0, FLDSET(struct global_config, max_forwards));
 	ast_sorcery_object_field_register(sorcery, "global", "user_agent", default_useragent,
 			OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, useragent));
+	ast_sorcery_object_field_register(sorcery, "global", "default_outbound_endpoint", DEFAULT_OUTBOUND_ENDPOINT,
+			OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_outbound_endpoint));
 
 	return 0;
 }
diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h
index 0ee62529f603ffed2d9fafff2cac08b1b1e99803..368bdd04a6fe9f353182864d85150fb4289fb22c 100644
--- a/res/res_pjsip/include/res_pjsip_private.h
+++ b/res/res_pjsip/include/res_pjsip_private.h
@@ -105,4 +105,15 @@ int ast_sip_for_each_channel_snapshot(const struct ast_endpoint_snapshot *endpoi
 				      on_channel_snapshot_t on_channel_snapshot,
 				      void *arg);
 
+/*!
+ * \brief Retrieve the name of the default outbound endpoint.
+ *
+ * \note This returns a memory allocated copy of the name that
+ *       needs to be freed by the caller.
+ *
+ * \retval The name of the default outbound endpoint.
+ * \retval NULL if configuration not found.
+ */
+char *ast_sip_global_default_outbound_endpoint(void);
+
 #endif /* RES_PJSIP_PRIVATE_H_ */
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 3b9bfd6a7ae94d212517d7456d11a65435cf944d..010eeb6970a4ea09ba145f61051e0bcb9ad0864f 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1528,6 +1528,13 @@ struct ao2_container *ast_sip_get_endpoints(void)
 	return endpoints;
 }
 
+struct ast_sip_endpoint *ast_sip_default_outbound_endpoint(void)
+{
+	RAII_VAR(char *, name, ast_sip_global_default_outbound_endpoint(), ast_free);
+	return ast_strlen_zero(name) ? NULL : ast_sorcery_retrieve_by_id(
+		sip_sorcery, "endpoint", name);
+}
+
 int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
 {
 	int i;
diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c
index b66ee0b113b1e2c77e24d0993a7f7e9e663c9c3e..00923b23bad5a6ae249ab919e1ef3625a6245da7 100644
--- a/res/res_pjsip_messaging.c
+++ b/res/res_pjsip_messaging.c
@@ -80,13 +80,17 @@ static enum pjsip_status_code get_destination(const pjsip_rx_data *rdata, const
  */
 static enum pjsip_status_code check_content_type(const pjsip_rx_data *rdata)
 {
-	if (ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
-				    "text",
-				    "plain")) {
-		return PJSIP_SC_OK;
+	int res;
+	if (rdata->msg_info.msg->body && rdata->msg_info.msg->body->len) {
+		res = ast_sip_is_content_type(
+			&rdata->msg_info.msg->body->content_type, "text", "plain");
 	} else {
-		return PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
+		res = rdata->msg_info.ctype &&
+			!pj_strcmp2(&rdata->msg_info.ctype->media.type, "text") &&
+			!pj_strcmp2(&rdata->msg_info.ctype->media.subtype, "plain");
 	}
+
+	return res ? PJSIP_SC_OK : PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
 }
 
 /*!
@@ -96,9 +100,9 @@ static enum pjsip_status_code check_content_type(const pjsip_rx_data *rdata)
  *
  * \param fromto 'From' or 'To' field containing 'sip:'
  */
-static const char* skip_sip(const char *fromto)
+static char* skip_sip(char *fromto)
 {
-	const char *p;
+	char *p;
 
 	/* need to be one past 'sip:' or 'sips:' */
 	if (!(p = strstr(fromto, "sip"))) {
@@ -119,6 +123,7 @@ static const char* skip_sip(const char *fromto)
  * Expects the given 'fromto' to be in one of the following formats:
  *      sip[s]:endpoint[/aor]
  *      sip[s]:endpoint[/uri]
+ *      sip[s]:uri <-- will use default outbound endpoint
  *
  * If an optional aor is given it will try to find an associated uri
  * to return.  If an optional uri is given then that will be returned,
@@ -127,30 +132,37 @@ static const char* skip_sip(const char *fromto)
  * \param fromto 'From' or 'To' field with possible endpoint
  * \param uri Optional uri to return
  */
-static struct ast_sip_endpoint* get_endpoint(const char *fromto, char **uri)
+static struct ast_sip_endpoint* get_endpoint(char *fromto, char **uri)
 {
-	const char *name = skip_sip(fromto);
+	char *name, *aor_uri;
 	struct ast_sip_endpoint* endpoint;
-	struct ast_sip_aor *aor;
+	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
 
-	if ((*uri = strchr(name, '/'))) {
-		*(*uri)++ = '\0';
-	} else if ((*uri = strchr(name, '@'))) {
-		*(*uri) = '\0';
-	}
-
-	/* endpoint is required */
-	if (ast_strlen_zero(name)) {
-		return NULL;
+	name = skip_sip(fromto);
+	if ((aor_uri = strchr(name, '/'))) {
+		*aor_uri++ = '\0';
+	} else if ((aor_uri = strchr(name, '@'))) {
+		/* format was endpoint@ */
+		*aor_uri = '\0';
 	}
 
-	if (!(endpoint = ast_sorcery_retrieve_by_id(
+	if (ast_strlen_zero(name) || !(endpoint = ast_sorcery_retrieve_by_id(
 		      ast_sip_get_sorcery(), "endpoint", name))) {
-		return NULL;
+		/* assume sending to direct uri -
+		   use default outbound endpoint */
+		*uri = ast_strdup(fromto);
+		return ast_sip_default_outbound_endpoint();
 	}
 
-	if (*uri && (aor = ast_sip_location_retrieve_aor(*uri))) {
-		*uri = (char*)ast_sip_location_retrieve_first_aor_contact(aor)->uri;
+	*uri = aor_uri;
+	if (*uri) {
+		if ((aor = ast_sip_location_retrieve_aor(*uri)) &&
+			(contact = ast_sip_location_retrieve_first_aor_contact(aor))) {
+			*uri = (char*)contact->uri;
+		}
+		/* need to copy because contact-uri might go away*/
+		*uri = ast_strdup(*uri);
 	}
 
 	return endpoint;
@@ -163,13 +175,12 @@ static struct ast_sip_endpoint* get_endpoint(const char *fromto, char **uri)
  * \param tdata The outgoing message data structure
  * \param from Info to potentially copy into the 'From' header
  */
-static void update_from(pjsip_tx_data *tdata, const char *from)
+static void update_from(pjsip_tx_data *tdata, char *from)
 {
 	pjsip_name_addr *from_name_addr;
 	pjsip_sip_uri *from_uri;
 	pjsip_uri *parsed;
-	char *uri;
-
+	RAII_VAR(char *, uri, NULL, ast_free);
 	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
 
 	if (ast_strlen_zero(from)) {
@@ -182,7 +193,20 @@ static void update_from(pjsip_tx_data *tdata, const char *from)
 
 	if (ast_strlen_zero(uri)) {
 		/* if no aor/uri was specified get one from the endpoint */
-		uri = (char*)ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors)->uri;
+		RAII_VAR(struct ast_sip_contact *, contact,
+			 ast_sip_location_retrieve_contact_from_aor_list(
+				 endpoint->aors), ao2_cleanup);
+
+		if (!contact || ast_strlen_zero(contact->uri)) {
+			ast_log(LOG_WARNING, "No contact found for endpoint %s\n",
+				ast_sorcery_object_get_id(endpoint));
+			return;
+		}
+
+		if (uri) {
+			ast_free(uri);
+		}
+		uri = ast_strdup(contact->uri);
 	}
 
 	/* get current 'from' hdr & uri - going to overwrite some fields */
@@ -341,6 +365,7 @@ static enum pjsip_status_code vars_to_headers(const struct ast_msg *msg, pjsip_t
 static int headers_to_vars(const pjsip_rx_data *rdata, struct ast_msg *msg)
 {
 	char *c;
+	char name[MAX_HDR_SIZE];
 	char buf[MAX_HDR_SIZE];
 	int res = 0;
 	pjsip_hdr *h = rdata->msg_info.msg->hdr.next;
@@ -350,10 +375,11 @@ static int headers_to_vars(const pjsip_rx_data *rdata, struct ast_msg *msg)
 		if ((res = pjsip_hdr_print_on(h, buf, sizeof(buf)-1)) > 0) {
 			buf[res] = '\0';
 			if ((c = strchr(buf, ':'))) {
-				ast_copy_string(buf, ast_skip_blanks(c + 1), sizeof(buf)-(c-buf));
+				ast_copy_string(buf, ast_skip_blanks(c + 1), sizeof(buf));
 			}
 
-			if ((res = ast_msg_set_var(msg, pj_strbuf(&h->name), buf)) != 0) {
+			ast_copy_pj_str(name, &h->name, sizeof(name));
+			if ((res = ast_msg_set_var(msg, name, buf)) != 0) {
 				break;
 			}
 		}
@@ -375,10 +401,14 @@ static int headers_to_vars(const pjsip_rx_data *rdata, struct ast_msg *msg)
  */
 static int print_body(pjsip_rx_data *rdata, char *buf, int len)
 {
-	int res = rdata->msg_info.msg->body->print_body(
-		rdata->msg_info.msg->body, buf, len);
+	int res;
+
+	if (!rdata->msg_info.msg->body || !rdata->msg_info.msg->body->len) {
+		return 0;
+	}
 
-	if (res < 0) {
+	if ((res = rdata->msg_info.msg->body->print_body(
+		     rdata->msg_info.msg->body, buf, len)) < 0) {
 		return res;
 	}
 
@@ -500,30 +530,32 @@ static int msg_send(void *data)
 	};
 
 	pjsip_tx_data *tdata;
-	char *uri;
-
+	RAII_VAR(char *, uri, NULL, ast_free);
 	RAII_VAR(struct ast_sip_endpoint *, endpoint, get_endpoint(
 			 mdata->to, &uri), ao2_cleanup);
+
 	if (!endpoint) {
-		ast_log(LOG_ERROR, "SIP MESSAGE - Endpoint not found in %s\n", mdata->to);
+		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint and "
+			"no default outbound endpoint configured\n");
 		return -1;
 	}
 
 	if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, &tdata)) {
-		ast_log(LOG_ERROR, "SIP MESSAGE - Could not create request\n");
+		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not create request\n");
 		return -1;
 	}
 
 	if (ast_sip_add_body(tdata, &body)) {
 		pjsip_tx_data_dec_ref(tdata);
-		ast_log(LOG_ERROR, "SIP MESSAGE - Could not add body to request\n");
+		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not add body to request\n");
 		return -1;
 	}
 
 	update_from(tdata, mdata->from);
 	vars_to_headers(mdata->msg, tdata);
+
 	if (ast_sip_send_request(tdata, NULL, endpoint)) {
-		ast_log(LOG_ERROR, "SIP MESSAGE - Could not send request\n");
+		ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n");
 		return -1;
 	}