smtp-submit.c revision 7112c5ac642aba8d96b5018c2d30ac014940654b
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2006-2017 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen#include "lib.h"
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen#include "ioloop.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "array.h"
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainen#include "str.h"
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen#include "istream.h"
cd94aeaa294f7cc507206b4b2075852f00e14d61Timo Sirainen#include "ostream.h"
cd94aeaa294f7cc507206b4b2075852f00e14d61Timo Sirainen#include "iostream-temp.h"
cd94aeaa294f7cc507206b4b2075852f00e14d61Timo Sirainen#include "master-service.h"
cd94aeaa294f7cc507206b4b2075852f00e14d61Timo Sirainen#include "program-client.h"
cd94aeaa294f7cc507206b4b2075852f00e14d61Timo Sirainen#include "lmtp-client.h"
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen#include "smtp-submit.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <unistd.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <sys/wait.h>
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include <sysexits.h>
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen#include <signal.h>
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen#define DEFAULT_SUBMISSION_PORT 25
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct smtp_submit_session {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pool_t pool;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct smtp_submit_settings set;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen};
cd94aeaa294f7cc507206b4b2075852f00e14d61Timo Sirainen
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainenstruct smtp_submit {
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen pool_t pool;
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen struct smtp_submit_session *session;
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen struct ostream *output;
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen struct istream *input;
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen ARRAY_TYPE(const_string) destinations;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *return_path;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct timeout *to_error;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int status;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *error;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct program_client *prg_client;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct lmtp_client *lmtp_client;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen smtp_submit_callback_t *callback;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen void *context;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen bool simple:1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen};
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct smtp_submit_session *
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainensmtp_submit_session_init(const struct smtp_submit_settings *set)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct smtp_submit_session *session;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pool_t pool;
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pool = pool_alloconly_create("smtp submit session", 128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen session = p_new(pool, struct smtp_submit_session, 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen session->pool = pool;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen session->set = *set;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen session->set.hostname = p_strdup_empty(pool, set->hostname);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen session->set.submission_host = p_strdup_empty(pool, set->submission_host);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen session->set.sendmail_path = p_strdup_empty(pool, set->sendmail_path);
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen return session;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid smtp_submit_session_deinit(struct smtp_submit_session **_session)
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen{
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen struct smtp_submit_session *session = *_session;
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen *_session = NULL;
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pool_unref(&session->pool);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstruct smtp_submit *
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainensmtp_submit_init(struct smtp_submit_session *session, const char *return_path)
64e244defe74f513ce94f33d000a048ddbe2ea23Timo Sirainen{
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen struct smtp_submit *subm;
12cf3d0e03fc70fb0c8b91bc8fd83b4e14d7cdefTimo Sirainen pool_t pool;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen pool = pool_alloconly_create("smtp submit", 256);
bf72c930996df0691932fb1143f360d260f27a06Timo Sirainen subm = p_new(pool, struct smtp_submit, 1);
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen subm->session = session;
cd94aeaa294f7cc507206b4b2075852f00e14d61Timo Sirainen subm->pool = pool;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen subm->return_path = p_strdup(pool, return_path);
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen p_array_init(&subm->destinations, pool, 2);
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen return subm;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
bbba7d0fce1b6ce5baa2d7ef946eb1b63e2ab518Timo Sirainen
bbba7d0fce1b6ce5baa2d7ef946eb1b63e2ab518Timo Sirainenstruct smtp_submit *
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainensmtp_submit_init_simple(const struct smtp_submit_settings *set,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *return_path)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct smtp_submit_session *session;
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainen struct smtp_submit *subm;
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen session = smtp_submit_session_init(set);
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainen subm = smtp_submit_init(session, return_path);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen subm->simple = TRUE;
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainen return subm;
bf72c930996df0691932fb1143f360d260f27a06Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
02ccba3d3be96444abd15b5254864c9151bbeb30Timo Sirainenvoid smtp_submit_deinit(struct smtp_submit **_subm)
087939d3fa9c4056419386c9d6c81f147de534cdTimo Sirainen{
02ccba3d3be96444abd15b5254864c9151bbeb30Timo Sirainen struct smtp_submit *subm = *_subm;
bf72c930996df0691932fb1143f360d260f27a06Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *_subm = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (subm->output != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_destroy(&subm->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (subm->input != NULL)
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainen i_stream_destroy(&subm->input);
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen if (subm->prg_client != NULL)
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainen program_client_destroy(&subm->prg_client);
02ccba3d3be96444abd15b5254864c9151bbeb30Timo Sirainen if (subm->lmtp_client != NULL)
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen lmtp_client_deinit(&subm->lmtp_client);
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (subm->to_error != NULL)
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen timeout_remove(&subm->to_error);
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen if (subm->simple)
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen smtp_submit_session_deinit(&subm->session);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pool_unref(&subm->pool);
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen}
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainenvoid smtp_submit_add_rcpt(struct smtp_submit *subm, const char *address)
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen{
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen i_assert(subm->output == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen address = p_strdup(subm->pool, address);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen array_append(&subm->destinations, &address, 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainenstruct ostream *smtp_submit_send(struct smtp_submit *subm)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(subm->output == NULL);
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen i_assert(array_count(&subm->destinations) > 0);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen subm->output = iostream_temp_create
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (t_strconcat("/tmp/dovecot.",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen master_service_get_name(master_service), NULL), 0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_set_no_error_handling(subm->output, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return subm->output;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainensmtp_submit_callback(struct smtp_submit *subm, int status,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *error)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen struct smtp_submit_result result;
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen smtp_submit_callback_t *callback;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (subm->to_error != NULL)
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen timeout_remove(&subm->to_error);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen i_zero(&result);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen result.status = status;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen result.error = error;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen callback = subm->callback;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen subm->callback = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen callback(&result, subm->context);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
c49a19168dab6fda80aee16ad799a8a56d3bc18fTimo Sirainenstatic void
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainensmtp_submit_delayed_error_callback(struct smtp_submit *subm)
71f1783adc89b4fe3588c72b23e059b320da8fadTimo Sirainen{
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen smtp_submit_callback(subm, -1, subm->error);
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen}
caea325346da6fb1cf503b35a619467a997acbfaTimo Sirainen
caea325346da6fb1cf503b35a619467a997acbfaTimo Sirainenstatic void
caea325346da6fb1cf503b35a619467a997acbfaTimo Sirainensmtp_submit_delayed_error(struct smtp_submit *subm,
c0a708fa3f7b8f4fbca32052da5faf7a0125189dTimo Sirainen const char *error)
{
subm->status = -1;
subm->error = p_strdup(subm->pool, error);
subm->to_error = timeout_add_short(0,
smtp_submit_delayed_error_callback, subm);
}
static void
smtp_submit_error(struct smtp_submit *subm,
int status, const char *error)
{
const struct smtp_submit_settings *set = &subm->session->set;
i_assert(status <= 0);
if (subm->error != NULL)
return;
subm->status = status;
subm->error = p_strdup_printf(subm->pool,
"smtp(%s): %s",
set->submission_host, error);
}
static void
smtp_submit_success(struct smtp_submit *subm)
{
if (subm->error != NULL)
return;
subm->status = 1;
}
static void
smtp_submit_send_host_finished(void *context)
{
struct smtp_submit *subm = (struct smtp_submit *)context;
i_assert(subm->status > 0 || subm->error != NULL);
smtp_submit_callback(subm, subm->status, subm->error);
}
static void
rcpt_to_callback(enum lmtp_client_result result, const char *reply, void *context)
{
struct smtp_submit *subm = (struct smtp_submit *)context;
if (result != LMTP_CLIENT_RESULT_OK) {
smtp_submit_error(subm,
(reply[0] != '5' ? -1 : 0),
t_strdup_printf("RCPT TO failed: %s", reply));
}
}
static void
data_callback(enum lmtp_client_result result, const char *reply, void *context)
{
struct smtp_submit *subm = (struct smtp_submit *)context;
if (result != LMTP_CLIENT_RESULT_OK) {
smtp_submit_error(subm,
(reply[0] != '5' ? -1 : 0),
t_strdup_printf("DATA failed: %s", reply));
return;
}
smtp_submit_success(subm);
}
static void
smtp_submit_send_host(struct smtp_submit *subm)
{
const struct smtp_submit_settings *set = &subm->session->set;
struct lmtp_client_settings client_set;
struct lmtp_client *lmtp_client;
const char *host, *const *destp;
in_port_t port;
if (net_str2hostport(set->submission_host,
DEFAULT_SUBMISSION_PORT, &host, &port) < 0) {
smtp_submit_delayed_error(subm, t_strdup_printf(
"Invalid submission_host: %s", host));
return;
}
i_zero(&client_set);
client_set.mail_from = subm->return_path == NULL ? "<>" :
t_strconcat("<", subm->return_path, ">", NULL);
client_set.my_hostname = set->hostname;
client_set.timeout_secs = set->submission_timeout;
lmtp_client = lmtp_client_init(&client_set,
smtp_submit_send_host_finished, subm);
if (lmtp_client_connect_tcp(lmtp_client, LMTP_CLIENT_PROTOCOL_SMTP,
host, port) < 0) {
smtp_submit_delayed_error(subm, t_strdup_printf(
"Couldn't connect to %s:%u", host, port));
lmtp_client_deinit(&lmtp_client);
return;
}
array_foreach(&subm->destinations, destp) {
lmtp_client_add_rcpt(lmtp_client, *destp, rcpt_to_callback,
data_callback, subm);
}
subm->lmtp_client = lmtp_client;
lmtp_client_send(lmtp_client, subm->input);
i_stream_unref(&subm->input);
}
static void
smtp_submit_sendmail_callback(int status, struct smtp_submit *subm)
{
if (status < 0) {
smtp_submit_callback(subm, -1,
"Failed to execute sendmail");
return;
}
if (status == 0) {
smtp_submit_callback(subm, -1,
"Sendmail program returned error");
return;
}
smtp_submit_callback(subm, 1, NULL);
}
static void
smtp_submit_send_sendmail(struct smtp_submit *subm)
{
const struct smtp_submit_settings *set = &subm->session->set;
const char *const *sendmail_args, *sendmail_bin, *str;
ARRAY_TYPE(const_string) args;
unsigned int i;
struct program_client_settings pc_set;
struct program_client *pc;
sendmail_args = t_strsplit(set->sendmail_path, " ");
t_array_init(&args, 16);
i_assert(sendmail_args[0] != NULL);
sendmail_bin = sendmail_args[0];
for (i = 1; sendmail_args[i] != NULL; i++)
array_append(&args, &sendmail_args[i], 1);
str = "-i"; array_append(&args, &str, 1); /* ignore dots */
str = "-f"; array_append(&args, &str, 1);
str = (subm->return_path != NULL &&
*subm->return_path != '\0' ?
subm->return_path : "<>");
array_append(&args, &str, 1);
str = "--"; array_append(&args, &str, 1);
array_append_array(&args, &subm->destinations);
array_append_zero(&args);
i_zero(&pc_set);
pc_set.client_connect_timeout_msecs = set->submission_timeout * 1000;
pc_set.input_idle_timeout_msecs = set->submission_timeout * 1000;
restrict_access_init(&pc_set.restrict_set);
pc = program_client_local_create
(sendmail_bin, array_idx(&args, 0), &pc_set);
program_client_set_input(pc, subm->input);
i_stream_unref(&subm->input);
subm->prg_client = pc;
program_client_run_async(pc, smtp_submit_sendmail_callback, subm);
}
struct smtp_submit_run_context {
int status;
char *error;
};
static void
smtp_submit_run_callback(const struct smtp_submit_result *result,
struct smtp_submit_run_context *rctx)
{
rctx->error = i_strdup(result->error);
rctx->status = result->status;
io_loop_stop(current_ioloop);
}
int smtp_submit_run(struct smtp_submit *subm,
const char **error_r)
{
struct smtp_submit_run_context rctx;
struct ioloop *ioloop;
ioloop = io_loop_create();
io_loop_set_running(ioloop);
i_zero(&rctx);
smtp_submit_run_async(subm,
smtp_submit_run_callback, &rctx);
if (io_loop_is_running(ioloop))
io_loop_run(ioloop);
io_loop_destroy(&ioloop);
if (rctx.error == NULL)
*error_r = NULL;
else {
*error_r = t_strdup(rctx.error);
i_free(rctx.error);
}
return rctx.status;
}
#undef smtp_submit_run_async
void smtp_submit_run_async(struct smtp_submit *subm,
smtp_submit_callback_t *callback, void *context)
{
const struct smtp_submit_settings *set = &subm->session->set;
subm->callback = callback;
subm->context = context;
/* the mail has been written to a file. now actually send it. */
subm->input = iostream_temp_finish
(&subm->output, IO_BLOCK_SIZE);
if (set->submission_host != NULL) {
smtp_submit_send_host(subm);
} else {
smtp_submit_send_sendmail(subm);
}
}