diff --git a/api/src/Mail.php b/api/src/Mail.php index 09150f2d2d..af11f64290 100644 --- a/api/src/Mail.php +++ b/api/src/Mail.php @@ -6209,7 +6209,7 @@ class Mail * @param string _body body part of message, only used if _header is NO resource * @param string _flags = '\\Recent'the imap flags to set for the saved message * - * @return the id of the message appended or exception + * @return int id of the message appended or exception * @throws Exception\WrongUserinput */ function appendMessage($_folderName, $_header, $_body, $_flags='\\Recent') diff --git a/doc/REST-CalDAV-CardDAV/Mail.md b/doc/REST-CalDAV-CardDAV/Mail.md index 626c2b3cf2..ad6f29c831 100644 --- a/doc/REST-CalDAV-CardDAV/Mail.md +++ b/doc/REST-CalDAV-CardDAV/Mail.md @@ -41,6 +41,7 @@ The content of the POST request is a JSON encoded object with following attribut - ```subject```: string with subject - ```body```: string plain text body (optional) - ```bodyHtml```: string with html body (optional) +- ```replyEml```: string returned from uploaded eml file to reply to (optional) - ```attachments```: array of strings returned from uploaded attachments (see below) or VFS path ```["/mail/attachments/", "/home//", ...]``` - ```attachmentType```: one of the following strings (optional, default "attach") - "attach" send as attachment diff --git a/mail/inc/class.mail_compose.inc.php b/mail/inc/class.mail_compose.inc.php index a6abd6b0b2..931610252d 100644 --- a/mail/inc/class.mail_compose.inc.php +++ b/mail/inc/class.mail_compose.inc.php @@ -1014,9 +1014,31 @@ class mail_compose $_content[$name]=$content[$name]=$_REQUEST['preset'][$name]; } //skip if already processed by "preset Routines" - if ($alreadyProcessed[$name]) continue; - //error_log(__METHOD__.__LINE__.':'.$name.'->'. $_REQUEST['preset'][$name]); - if (!empty($_REQUEST['preset'][$name])) $content[$name] = $_REQUEST['preset'][$name]; + if ($alreadyProcessed[$name] || empty($_REQUEST['preset'][$name])) + { + continue; + } + if ($name === 'body' && !empty($content['body'])) + { + // if preset body has different mimeType the (reply-)body --> convert all to html + if ($content['mimeType'] !== $_REQUEST['preset']['mimeType']) + { + if ($_REQUEST['preset']['mimeType'] === 'plain') + { + $_REQUEST['preset']['body'] = '

'.nl2br($_REQUEST['preset']['body'])."

\n"; + } + else + { + $content['body'] = '
'.$content['body']."
\n"; + } + $content['mimeType'] = $_REQUEST['preset']['mimeType'] = 'html'; + } + $content['body'] = $_REQUEST['preset']['body'].$content['body']; + } + else + { + $content[$name] = $_REQUEST['preset'][$name]; + } } // if we preset the body, we always want the signature below (independent of user preference for replay or forward!) if (!empty($_REQUEST['preset']['body'])) diff --git a/mail/src/ApiHandler.php b/mail/src/ApiHandler.php index 8d042dc3bc..ff327f6d11 100644 --- a/mail/src/ApiHandler.php +++ b/mail/src/ApiHandler.php @@ -75,7 +75,7 @@ class ApiHandler extends Api\CalDAV\Handler } elseif (preg_match('#^/mail(/(\d+))?(/compose)?#', $path, $matches)) { - $ident_id = $matches[2] ?? self::defaultIdentity($user); + $ident_id = $matches[2] ?? null ?: self::defaultIdentity($user); $do_compose = (bool)($matches[3] ?? false); if (!($data = json_decode($options['content'], true))) { @@ -83,7 +83,33 @@ class ApiHandler extends Api\CalDAV\Handler } // ToDo: check required attributes - $preset = array_filter(array_intersect_key($data, array_flip(['to', 'cc', 'bcc', 'replyto', 'subject', 'priority']))+[ + $params = []; + + // should we reply to an eml file + if (!empty($data['replyEml'])) + { + if (preg_match('#^/mail/attachments/(([^/]+)--[^/.-]{6,})$#', $data['replyEml'], $matches) && + file_exists($eml=$GLOBALS['egw_info']['server']['temp_dir'].'/attach--'.$matches[1])) + { + // import mail into drafts folder + $acc_id = Api\Mail\Account::read_identity($ident_id)['acc_id']; + $mail = Api\Mail::getInstance(false, $acc_id); + $folder = $mail->getDraftFolder(); + $mailer = new Api\Mailer(); + $mail->parseFileIntoMailObject($mailer, $eml); + $mail->openConnection(); + $uid = $mail->appendMessage($folder, $mailer->getRaw(), null, '\\Seen'); + // and generate row-id from it to pass as reply_id to compose + $params['reply_id'] = \mail_ui::generateRowID($acc_id, $folder, $uid, true); + $params['from'] = 'reply'; + } + else + { + throw new \Exception("Reply message eml '{$data['reply_eml']}' NOT found", 400); + } + } + + $preset = array_filter(array_intersect_key($data, array_flip(['to', 'cc', 'bcc', 'replyto', 'subject', 'priority', 'reply_id']))+[ 'body' => $data['bodyHtml'] ?? null ?: $data['body'] ?? '', 'mimeType' => !empty($data['bodyHtml']) ? 'html' : 'plain', 'identity' => $ident_id, @@ -99,7 +125,7 @@ class ApiHandler extends Api\CalDAV\Handler throw new \Exception("User '$account_lid' (#$user) is NOT online", 404); } $push = new Api\Json\Push($user); - $push->call('egw.open', '', 'mail', 'add', ['preset' => $preset], '_blank', 'mail'); + $push->call('egw.open', '', 'mail', 'add', $params+['preset' => $preset], '_blank', 'mail'); echo json_encode([ 'status' => 200, 'message' => 'Request to open compose window sent', @@ -107,7 +133,7 @@ class ApiHandler extends Api\CalDAV\Handler ], self::JSON_RESPONSE_OPTIONS); return true; } - $acc_id = Api\Mail\Account::read_identity($ident_id)['acc_id']; + $acc_id = $acc_id ?? Api\Mail\Account::read_identity($ident_id)['acc_id']; $mail_account = Api\Mail\Account::read($acc_id); // check if the mail-account requires a user-context / password and then just send the mail with an smtp-only account NOT saving to Sent folder if (empty($mail_account->acc_imap_password) || $mail_account->acc_smtp_auth_session && empty($mail_account->acc_smtp_password))