1 頁 (共 1 頁)

OCS email 增加 reply-to 的功能,以因應gmail發信的需求

發表於 : 2025-04-11, 19:41
dtchang
需修改的檔案(必要):
D:\Inetpub\ocs\lib\pkp\classes\mail\Mail.inc.php
D:\Inetpub\ocs\classes\mail\MailTemplate.inc.php
可使用 chatgpt 發問如何在 ocs 研討會系統中增加 email 的 reply-to 功能
D:\Inetpub\ocs\lib\pkp\classes\mail\PKPMailTemplate.inc.php 裡也有 send() 也可以考慮加入 reply-to

------------------------------------------------------

D:\Inetpub\ocs\lib\pkp\classes\mail\Mail.inc.php 修改 send() 及新增函式(在 send() 之前即可):

代碼: 選擇全部

//TODO FIXME
//新增 reply-to 功能
function setReplyTo($email, $name = '') {
	//error_log("setReplyTo {$name} <{$email}>"); // 除錯用
	return $this->setData('replyTo', array('name' => $name, 'email' => $email));
}

function getReplyTo() {
	return $this->getData('replyTo');
}
修改 send()

代碼: 選擇全部

	/**
	 * Send the email.
	 * @return boolean
	 */
	function send() {
//TODO FIXME
// 嘗試自動設定 Reply-To 為登入使用者(主編/作者)email
if ($this->getReplyTo() === null) {
    $user =& Request::getUser();
    if ($user) {
        $this->setReplyTo($user->getEmail(), $user->getFullName());
    }
}

		$recipients = $this->getAddressArrayString($this->getRecipients(), true, true);
		$from = $this->getFromString(true);

		$subject = String::encode_mime_header($this->getSubject());
		$body = $this->getBody();

    // 去掉錯誤的空白信(未設主旨)(不寄信但視為成功)
    preg_match('/(.+\])(.*)/', $subject, $matches);
    if(isset($matches[2]) and !is_null($matches[1]) and 
	  (is_null($matches[2]) or empty($matches[2])))
     {
     	//error_log("Bad email!"); 
     	return true;
     }

		// FIXME Some *nix mailers won't work with CRLFs
		if (Core::isWindows()) {
			// Convert LFs to CRLFs for Windows
			$body = String::regexp_replace("/([^\r]|^)\n/", "\$1\r\n", $body);
		} else {
			// Convert CRLFs to LFs for *nix
			$body = String::regexp_replace("/\r\n/", "\n", $body);
		}

		if ($this->getContentType() != null) {
			$this->addHeader('Content-Type', $this->getContentType());
		} elseif ($this->hasAttachments()) {
			// Only add MIME headers if sending an attachment
			$mimeBoundary = '==boundary_'.md5(microtime());

			/* Add MIME-Version and Content-Type as headers. */
			$this->addHeader('MIME-Version', '1.0');
			$this->addHeader('Content-Type', 'multipart/mixed; boundary="'.$mimeBoundary.'"');

		} else {
			$this->addHeader('Content-Type', 'text/plain; charset="'.Config::getVar('i18n', 'client_charset').'"');
		}

		$this->addHeader('X-Mailer', 'Public Knowledge Project Suite v2');

		$remoteAddr = Request::getRemoteAddr();
		if ($remoteAddr != '') $this->addHeader('X-Originating-IP', $remoteAddr);

		$this->addHeader('Date', date('D, d M Y H:i:s O'));

		/* Add $from, $ccs, and $bccs as headers. */
		if ($from != null) {
			$this->addHeader('From', $from);
		}

		$ccs = $this->getAddressArrayString($this->getCcs(), true, true);
		if ($ccs != null) {
			$this->addHeader('Cc', $ccs);
		}

		$bccs = $this->getAddressArrayString($this->getBccs(), false, true);
		if ($bccs != null) {
			$this->addHeader('Bcc', $bccs);
		}

		$headers = '';
//TODO FIXME
$replyTo = $this->getReplyTo();
//error_log("Reply-To DATA: $replyTo"); // 除錯用
if ($replyTo !== null) {
    $formattedReplyTo = $this->getAddressArrayString(array($replyTo), true, true);
    //error_log("Reply-To Header Set: $formattedReplyTo"); // 除錯用
    $this->addHeader('Reply-To', $formattedReplyTo);
}
		foreach ($this->getHeaders() as $header) {
			if (!empty($headers)) {
				$headers .= MAIL_EOL;
			}
			$headers .= $header['name'].': '. str_replace(array("\r", "\n"), '', $header['content']);
		}

		if ($this->hasAttachments()) {
			// Add the body
			$mailBody = 'This message is in MIME format and requires a MIME-capable mail client to view.'.MAIL_EOL.MAIL_EOL;
			$mailBody .= '--'.$mimeBoundary.MAIL_EOL;
			$mailBody .= sprintf('Content-Type: text/plain; charset=%s', Config::getVar('i18n', 'client_charset')) . MAIL_EOL.MAIL_EOL;
			$mailBody .= wordwrap($body, MAIL_WRAP, MAIL_EOL).MAIL_EOL.MAIL_EOL;

			// Add the attachments
			$attachments = $this->getAttachments();
			foreach ($attachments as $attachment) {
				$mailBody .= '--'.$mimeBoundary.MAIL_EOL;
				$mailBody .= 'Content-Type: '.$attachment['content-type'].'; name="'.str_replace('"', '', $attachment['filename']).'"'.MAIL_EOL;
				$mailBody .= 'Content-transfer-encoding: base64'.MAIL_EOL;
				$mailBody .= 'Content-disposition: '.$attachment['disposition'].MAIL_EOL.MAIL_EOL;
				$mailBody .= $attachment['content'].MAIL_EOL.MAIL_EOL;
			}

			$mailBody .= '--'.$mimeBoundary.'--';

		} else {
			// Just add the body
			$mailBody = wordwrap($body, MAIL_WRAP, MAIL_EOL);
		}

		if ($this->getEnvelopeSender() != null) {
			$additionalParameters = '-f ' . $this->getEnvelopeSender();
		} else {
			$additionalParameters = null;
		}



		if (HookRegistry::call('Mail::send', array(&$this, &$recipients, &$subject, &$mailBody, &$headers, &$additionalParameters))) return;

		// Replace all the private parameters for this message.
		if (is_array($this->privateParams)) {
			foreach ($this->privateParams as $name => $value) {
				$mailBody = str_replace($name, $value, $mailBody);
			}
		}

		if (Config::getVar('email', 'smtp')) {
			$smtp =& Registry::get('smtpMailer', true, null);
			if ($smtp === null) {
				import('mail.SMTPMailer');
				$smtp = new SMTPMailer();
			}
			$sent = $smtp->mail($this, $recipients, $subject, $mailBody, $headers);
		} else {
			$sent = String::mail($recipients, $subject, $mailBody, $headers, $additionalParameters);
		}

		if (!$sent) {
			if (Config::getVar('debug', 'display_errors')) {
				if (Config::getVar('email', 'smtp')) {
					fatalError("There was an error sending this email.  Please check your PHP error log for more information.");
					return false;
				} else {
					fatalError("There was an error sending this email.  Please check your mail log (/var/log/maillog).");
					return false;
				}
			} else return false;
		} else return true;
	}
----------------------------------------------------------------------------------

D:\Inetpub\ocs\classes\mail\MailTemplate.inc.php 修改 send()

代碼: 選擇全部

	/**
	 * Send the email.
	 * Aside from calling the parent method, this actually attaches
	 * the persistent attachments if they are used.
	 * @param $clearAttachments boolean Whether to delete attachments after
	 */
//TODO FIXME
function send($clearAttachments = true) {
	$schedConf =& Request::getSchedConf();

	if ($schedConf) {
		$envelopeSender = $schedConf->getSetting('envelopeSender');
		$emailSignature = $schedConf->getLocalizedSetting('emailSignature');
	}

	if (isset($emailSignature)) {
		$searchString = '{$templateSignature}';
		if (strstr($this->getBody(), $searchString) === false) {
			$this->setBody($this->getBody() . "\n" . $emailSignature);
		} else {
			$this->setBody(str_replace($searchString, $emailSignature, $this->getBody()));
		}

		if (!empty($envelopeSender) && Config::getVar('email', 'allow_envelope_sender')) {
			$this->setEnvelopeSender($envelopeSender);
		}
	}

	// ✅ 判斷是否為登入使用者 → 設定 Reply-To
	$user =& Request::getUser();
	if ($user) {
		// 使用者登入 → 設定使用者為 Reply-To
		$this->setReplyTo($user->getEmail(), $user->getFullName());
	} else {
		// 系統自動信 → 設定為 no-reply@domain
		$from = $this->getFrom();
		if (isset($from['email']) && strpos($from['email'], '@') !== false) {
			$domain = substr(strrchr($from['email'], "@"), 1); // chu.edu.tw
			$this->setReplyTo('no-reply@' . $domain, '系統通知信');
		}
	}

	return parent::send($clearAttachments);
}