Version 4.7.0

This commit is contained in:
Neo committed 2025-12-19 16:00:35 -08:00
1 parent 517a5e1f70
commit 8ba7d43898
1933 files changed
+65613 -11332

No files matched your search

+42 -22
View File
@@ -66,6 +66,21 @@ abstract class _Email
* @brief The number of emails that can be sent in one "go"
*/
const MAX_EMAILS_PER_GO = \IPS\BULK_MAILS_PER_CYCLE;
/**
* @brief Use the NoWrapper wrapper (basic HTML container)
*/
const WRAPPER_NONE = 0;
/**
* @brief Use the full email wrapper
*/
const WRAPPER_USE = 1;
/**
* @brief A wrapper has already been applied to the email content ( used in MergeAndSend() )
*/
const WRAPPER_APPLIED = 2;
/* !Factory Constructors */
@@ -89,10 +104,6 @@ abstract class _Email
{
return 'IPS\Email\Outgoing\Smtp';
}
elseif ( \IPS\CIC2 )
{
return 'IPS\Cicloud\Email';
}
elseif ( \IPS\CIC )
{
return 'IPS\Email\Outgoing\IpsCic';
@@ -143,16 +154,16 @@ abstract class _Email
/**
* Initiate a new custom email based on raw email content.
*
* @param string $subject Subject
* @param string $htmlContent HTML Version
* @param string|NULL $plaintextContent Plaintext version. If not provided, one will be built automatically based off $htmlContent.
* @param string $type See TYPE_* constants.
* @param bool $useWrapper If TRUE, the email will be wrapped in the default wrapper template
* @param string $emailKey Key used to identify the email, used for tracking purposes
* @param bool $trackingEnabled TRUE by default, pass FALSE to explicitly disable log/view tracking. Useful with mergeAndSend()'s default behavior of rebuilding an already built email
* @param string $subject Subject
* @param string $htmlContent HTML Version
* @param string|NULL $plaintextContent Plaintext version. If not provided, one will be built automatically based off $htmlContent.
* @param string $type See TYPE_* constants.
* @param int $useWrapper See WRAPPER_* constants.
* @param string $emailKey Key used to identify the email, used for tracking purposes
* @param bool $trackingEnabled TRUE by default, pass FALSE to explicitly disable log/view tracking. Useful with mergeAndSend()'s default behavior of rebuilding an already built email
* @return \IPS\Email
*/
public static function buildFromContent( $subject, $htmlContent='', $plaintextContent=NULL, $type = NULL, $useWrapper=TRUE, $emailKey=NULL, $trackingEnabled=TRUE )
public static function buildFromContent( $subject, $htmlContent='', $plaintextContent=NULL, $type = NULL, $useWrapper=\IPS\Email::WRAPPER_USE, $emailKey=NULL, $trackingEnabled=TRUE )
{
if( !$type )
{
@@ -167,6 +178,12 @@ abstract class _Email
}
}
if( \IPS\IN_DEV AND \is_bool( $useWrapper ) )
{
trigger_error( "The email wrapper must be passed a constant when calling buildFromContent()", E_USER_ERROR );
exit;
}
$email = static::factory( $type );
$email->type = $type;
$email->subject = $subject;
@@ -242,7 +259,7 @@ abstract class _Email
/**
* @brief Should the default wrapper template be used?
*/
protected $useWrapper = TRUE;
protected $useWrapper = self::WRAPPER_USE;
/**
* @brief Unsubscribe Template App
@@ -349,9 +366,12 @@ abstract class _Email
{
$return = static::template( $this->templateApp, $this->templateKey, $type, array_merge( $this->templateParams, array( $this ) ) );
}
/* Check whether we have a subject yet, if not generate it */
$subject = $this->subject ?? $this->compileSubject( $member ?: NULL, $language );
/* Wrap in the wrapper if necessary */
if ( $this->useWrapper )
if ( $this->useWrapper == static::WRAPPER_USE )
{
/* Compile the unsubscribe link */
$unsubscribe = '';
@@ -368,11 +388,11 @@ abstract class _Email
}
/* Wrap */
$return = static::template( 'core', 'emailWrapper', $type, array( $this->subject, $member ?: new \IPS\Member, $return, $unsubscribe, $member === FALSE, '', $this, $ourPicks ) );
$return = static::template( 'core', 'emailWrapper', $type, array( $subject, $member ?: new \IPS\Member, $return, $unsubscribe, $member === FALSE, '', $this, $ourPicks ) );
}
else
elseif( $this->useWrapper == static::WRAPPER_NONE )
{
$return = static::template( 'core', 'emailNoWrapper', $type, array( $this->subject, $member ?: new \IPS\Member, $return, '', $member === FALSE, '', $this, NULL ) );
$return = static::template( 'core', 'emailNoWrapper', $type, array( $subject, $member ?: new \IPS\Member, $return, '', $member === FALSE, '', $this, NULL ) );
}
/* Parse language */
@@ -484,7 +504,7 @@ abstract class _Email
/**
* Get subject
*
* @param \IPS\Member|NULL|FALSE $member If the email is going to a member, the member object. Ensures correct language is used and the email starts with "Hi {member}". NULL for no member, FALSE to use "Hi *|member_name|*" for mergeAndSend()
* @param \IPS\Member|NULL $member If the email is going to a member, the member object. Ensures correct language is used and the email starts with "Hi {member}". NULL for no member, FALSE to use "Hi *|member_name|*" for mergeAndSend()
* @param \IPS\Lang|NULL $language If provided, will override the $member language
* @return string
*/
@@ -712,7 +732,7 @@ abstract class _Email
/* Sent successfully, remove notification */
\IPS\core\AdminNotification::remove( 'core', 'ConfigurationError', 'failedMail' );
\IPS\Db::i()->update( 'core_mail_error_logs', array( 'mlog_notification_sent' => TRUE ) );
\IPS\Db::i()->update( 'core_mail_error_logs', [ 'mlog_notification_sent' => TRUE ], [ 'mlog_notification_sent=?', 0 ] );
/* Update the ad impression count if appropriate */
if( $updateAds === TRUE )
@@ -824,7 +844,7 @@ abstract class _Email
* @param mixed $fromEmail The email address to send from. If NULL, default setting is used. NOTE: This should always be a site-controlled domin. Some services like Sparkpost require the domain to be validated.
* @param mixed $fromName The name the email should appear from. If NULL, default setting is used
* @param array $additionalHeaders Additional headers to send. Merge tags can be used like in content.
* @param \IPS\Lang $language The language the email content should be in
* @param \IPS\Lang|NULL $language The language the email content should be in
* @return int Number of successful sends
*/
public function mergeAndSend( $recipients, $fromEmail = NULL, $fromName = NULL, $additionalHeaders = array(), \IPS\Lang $language = NULL )
@@ -863,7 +883,7 @@ abstract class _Email
}
}
if ( static::buildFromContent( $subject, $htmlContent, $plaintextContent, $this->type, FALSE, $this->templateKey, FALSE )->send( $address, array(), array(), $fromEmail, $fromName, $_additionalHeaders, TRUE, FALSE ) )
if ( static::buildFromContent( $subject, $htmlContent, $plaintextContent, $this->type, static::WRAPPER_APPLIED, $this->templateKey, FALSE )->send( $address, array(), array(), $fromEmail, $fromName, $_additionalHeaders, TRUE, FALSE ) )
{
$return++;
}
+1 -2
View File
@@ -809,8 +809,7 @@ class _Email
}
/* If any of these headers are present with any values, ignore the email */
if( !empty( $this->headers['x-auto-response-suppress'] ) OR
!empty( $this->headers['x-autorespond'] ) OR
if( !empty( $this->headers['x-autorespond'] ) OR
!empty( $this->headers['x-autoreply'] ) OR
!empty( $this->headers['x-autoreply-From'] ) OR
!empty( $this->headers['x-mail-autoreply'] )
+3 -3
View File
@@ -54,15 +54,15 @@ class _Debug extends \IPS\Email
{
if( !is_dir( $this->debugPath ) )
{
throw new \IPS\Email\Outgoing\Exception( 'no_path_email_debug', 0, NULL, array( $this->debugPath ) );
throw new \IPS\Email\Outgoing\Exception( 'no_path_email_debug', 1, NULL, array( $this->debugPath ) );
}
$fullEmailContents = $this->compileFullEmail( $to, $cc, $bcc, $fromEmail, $fromName, $additionalHeaders );
$filename = date("M-j-Y") . '-' . microtime() . '-' . urlencode( mb_substr( $this->_parseRecipients( $to, TRUE ), 0, 200 ) ) . ".eml";
if( !@\file_put_contents( rtrim( $this->debugPath, '/' ) . '/' . $filename, $fullEmailContents ) )
{
throw new \IPS\Email\Outgoing\Exception( 'no_write_email_debug', 0, NULL, array( rtrim( $this->debugPath, '/' ) . '/' . $filename ) );
throw new \IPS\Email\Outgoing\Exception( 'no_write_email_debug', 2, NULL, array( rtrim( $this->debugPath, '/' ) . '/' . $filename ) );
}
}
}
+7
View File
@@ -40,6 +40,13 @@ class _Exception extends \RuntimeException
{
/* Store these for the extraLogData() method */
$this->extraDetails = $extra;
switch ( $code )
{
default:
$message = \IPS\Member::loggedIn()->language()->addToStack( $message, FALSE, array( 'sprintf' => $extra ) );
break;
}
return parent::__construct( $message, $code, $previous );
}
+7 -2
View File
@@ -35,7 +35,12 @@ class _PHP extends \IPS\Email
* @throws \IPS\Email\Outgoing\Exception
*/
public function _send( $to, $cc=array(), $bcc=array(), $fromEmail = NULL, $fromName = NULL, $additionalHeaders = array() )
{
{
if( !\function_exists( 'mail' ) )
{
throw new \IPS\Email\Outgoing\Exception( 'email_test_mailfunction_disabled' );
}
$boundary = "--==_mimepart_" . md5( mt_rand() );
$subject = $this->compileSubject( static::_getMemberFromRecipients( $to ) );
@@ -50,7 +55,7 @@ class _PHP extends \IPS\Email
try
{
if ( !mail( $this->_parseRecipients( $to, TRUE ), static::encodeHeader( $subject ), $this->_compileMessage( static::_getMemberFromRecipients( $to ), $boundary, PHP_EOL, 68 ), implode( PHP_EOL, $headers ), \IPS\Settings::i()->php_mail_extra ) )
if ( !mail( $this->_parseRecipients( $to, TRUE ), static::encodeHeader( $subject ), $this->_compileMessage( static::_getMemberFromRecipients( $to ), $boundary, "\r\n", 68 ), implode( "\r\n", $headers ), \IPS\Settings::i()->php_mail_extra ) )
{
if ( $error = \IPS\IPS::$lastError )
{
+2 -2
View File
@@ -124,10 +124,10 @@ class _SendGrid extends \IPS\Email
* @param mixed $fromEmail The email address to send from. If NULL, default setting is used. NOTE: This should always be a site-controlled domin. Some services like Sparkpost require the domain to be validated.
* @param mixed $fromName The name the email should appear from. If NULL, default setting is used
* @param array $additionalHeaders Additional headers to send. Merge tags can be used like in content.
* @param \IPS|Lang $language The language the email content should be in
* @param \IPS\Lang|NULL $language The language the email content should be in
* @return int Number of successful sends
*/
public function mergeAndSend( $recipients, $fromEmail = NULL, $fromName = NULL, $additionalHeaders = array(), \IPS\Lang $language )
public function mergeAndSend( $recipients, $fromEmail = NULL, $fromName = NULL, $additionalHeaders = array(), \IPS\Lang $language = NULL )
{
/* Initiate the request */
$request = $this->_initRequest( $fromEmail, $fromName );