diff --git a/composer.json b/composer.json
index 92a29565..aba1a887 100644
--- a/composer.json
+++ b/composer.json
@@ -83,7 +83,8 @@
"ext-libxml": "*",
"ext-gd": "*",
"ext-curl": "*",
- "ext-fileinfo": "*"
+ "ext-fileinfo": "*",
+ "setasign/fpdf": "^1.8"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
diff --git a/config/parameters.yml.dist b/config/parameters.yml.dist
index 92b33bed..38e54bf3 100644
--- a/config/parameters.yml.dist
+++ b/config/parameters.yml.dist
@@ -31,6 +31,10 @@ parameters:
env(APP_DEV_EMAIL): 'dev@dev.com'
app.powered_by_phplist: '%%env(APP_POWERED_BY_PHPLIST)%%'
env(APP_POWERED_BY_PHPLIST): '0'
+ app.preference_page_show_private_lists: '%%env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS)%%'
+ env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS): '0'
+ app.rest_api_domain: '%%env(REST_API_DOMAIN)%%'
+ env(REST_API_DOMAIN): 'https://example.com/api/v2'
# Email configuration
app.mailer_from: '%%env(MAILER_FROM)%%'
@@ -115,6 +119,12 @@ parameters:
env(EXTERNALIMAGE_TIMEOUT): '30'
messaging.external_image_max_size: '%%env(EXTERNALIMAGE_MAXSIZE)%%'
env(EXTERNALIMAGE_MAXSIZE): '204800'
+ messaging.forward_alternative_content: '%%env(FORWARD_ALTERNATIVE_CONTENT)%%'
+ env(FORWARD_ALTERNATIVE_CONTENT): '0'
+ messaging.email_text_credits: '%%env(EMAILTEXTCREDITS)%%'
+ env(EMAILTEXTCREDITS): '0'
+ messaging.always_add_user_track: '%%env(ALWAYS_ADD_USERTRACK)%%'
+ env(ALWAYS_ADD_USERTRACK): '1'
phplist.upload_images_dir: '%%env(PHPLIST_UPLOADIMAGES_DIR)%%'
env(PHPLIST_UPLOADIMAGES_DIR): 'images'
diff --git a/config/services/builders.yml b/config/services/builders.yml
index 10a994a4..4bc8d72f 100644
--- a/config/services/builders.yml
+++ b/config/services/builders.yml
@@ -4,22 +4,30 @@ services:
autoconfigure: true
public: false
- PhpList\Core\Domain\Messaging\Service\Builder\MessageBuilder:
- autowire: true
- autoconfigure: true
+ PhpList\Core\Domain\:
+ resource: '../../src/Domain/*/Service/Builder/*'
- PhpList\Core\Domain\Messaging\Service\Builder\MessageFormatBuilder:
- autowire: true
- autoconfigure: true
+ # Concrete mail constructors
+ PhpList\Core\Domain\Messaging\Service\Constructor\SystemMailContentBuilder: ~
+ PhpList\Core\Domain\Messaging\Service\Constructor\CampaignMailContentBuilder: ~
- PhpList\Core\Domain\Messaging\Service\Builder\MessageScheduleBuilder:
- autowire: true
- autoconfigure: true
+ # Two EmailBuilder services with different constructors injected
+ Core.EmailBuilder.system:
+ class: PhpList\Core\Domain\Messaging\Service\Builder\EmailBuilder
+ arguments:
+ $mailConstructor: '@PhpList\Core\Domain\Messaging\Service\Constructor\SystemMailContentBuilder'
+ $googleSenderId: '%messaging.google_sender_id%'
+ $useAmazonSes: '%messaging.use_amazon_ses%'
+ $usePrecedenceHeader: '%messaging.use_precedence_header%'
+ $devVersion: '%app.dev_version%'
+ $devEmail: '%app.dev_email%'
- PhpList\Core\Domain\Messaging\Service\Builder\MessageContentBuilder:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Builder\MessageOptionsBuilder:
- autowire: true
- autoconfigure: true
+ Core.EmailBuilder.campaign:
+ class: PhpList\Core\Domain\Messaging\Service\Builder\EmailBuilder
+ arguments:
+ $mailConstructor: '@PhpList\Core\Domain\Messaging\Service\Constructor\CampaignMailContentBuilder'
+ $googleSenderId: '%messaging.google_sender_id%'
+ $useAmazonSes: '%messaging.use_amazon_ses%'
+ $usePrecedenceHeader: '%messaging.use_precedence_header%'
+ $devVersion: '%app.dev_version%'
+ $devEmail: '%app.dev_email%'
diff --git a/config/services/managers.yml b/config/services/managers.yml
index 75475459..3b610913 100644
--- a/config/services/managers.yml
+++ b/config/services/managers.yml
@@ -4,53 +4,10 @@ services:
autoconfigure: true
public: false
- PhpList\Core\Domain\Configuration\Service\Manager\ConfigManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Configuration\Service\Manager\EventLogManager:
- autowire: true
- autoconfigure: true
+ PhpList\Core\Domain\:
+ resource: '../../src/Domain/*/Service/Manager/*'
- PhpList\Core\Domain\Identity\Service\SessionManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Identity\Service\AdministratorManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Identity\Service\AdminAttributeDefinitionManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Identity\Service\AdminAttributeManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Identity\Service\PasswordManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\SubscriberManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\SubscriberListManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\SubscriptionManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\AttributeDefinitionManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\DynamicListAttrManager:
- autowire: true
- autoconfigure: true
+ PhpList\Core\Bounce\Service\Manager\BounceManager: ~
Doctrine\DBAL\Schema\AbstractSchemaManager:
factory: ['@doctrine.dbal.default_connection', 'createSchemaManager']
@@ -62,55 +19,3 @@ services:
arguments:
$dbPrefix: '%database_prefix%'
$dynamicListTablePrefix: '%list_table_prefix%'
-
- PhpList\Core\Domain\Subscription\Service\Manager\SubscriberHistoryManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\SubscriberAttributeManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\SubscriberBlacklistManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Subscription\Service\Manager\SubscribePageManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\MessageManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\TemplateManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\TemplateImageManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\BounceRegexManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Bounce\Service\Manager\BounceManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\ListMessageManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\BounceRuleManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\SendProcessManager:
- autowire: true
- autoconfigure: true
-
- PhpList\Core\Domain\Messaging\Service\Manager\MessageDataManager:
- autowire: true
- autoconfigure: true
diff --git a/config/services/messenger.yml b/config/services/messenger.yml
index 3c8f27bb..98ceaf8e 100644
--- a/config/services/messenger.yml
+++ b/config/services/messenger.yml
@@ -5,34 +5,9 @@ services:
resource: '../../src/Domain/Messaging/MessageHandler'
tags: [ 'messenger.message_handler' ]
- PhpList\Core\Domain\Messaging\MessageHandler\SubscriberConfirmationMessageHandler:
- autowire: true
- autoconfigure: true
- tags: [ 'messenger.message_handler' ]
- arguments:
- $confirmationUrl: '%app.confirmation_url%'
-
- PhpList\Core\Domain\Messaging\MessageHandler\AsyncEmailMessageHandler:
- autowire: true
- autoconfigure: true
- tags: [ 'messenger.message_handler' ]
-
- PhpList\Core\Domain\Messaging\MessageHandler\PasswordResetMessageHandler:
- autowire: true
- autoconfigure: true
- tags: [ 'messenger.message_handler' ]
- arguments:
- $passwordResetUrl: '%app.password_reset_url%'
-
- PhpList\Core\Domain\Messaging\MessageHandler\SubscriptionConfirmationMessageHandler:
- autowire: true
- autoconfigure: true
- tags: [ 'messenger.message_handler' ]
-
PhpList\Core\Domain\Messaging\MessageHandler\CampaignProcessorMessageHandler:
autowire: true
-
- PhpList\Core\Domain\Subscription\MessageHandler\DynamicTableMessageHandler:
- autowire: true
autoconfigure: true
- tags: [ 'messenger.message_handler' ]
+ arguments:
+ $campaignEmailBuilder: '@Core.EmailBuilder.campaign'
+ $systemEmailBuilder: '@Core.EmailBuilder.system'
diff --git a/config/services/parameters.yml b/config/services/parameters.yml
index ebf1d99b..18aa6ccf 100644
--- a/config/services/parameters.yml
+++ b/config/services/parameters.yml
@@ -1,4 +1,9 @@
parameters:
+ # Flattened parameters for direct DI usage (Symfony does not support dot access into arrays)
+ app.config.message_from_address: 'news@example.com'
+ app.config.default_message_age: 15768000
+
+ # Keep original grouped array for legacy/config-provider usage
app.config:
message_from_address: 'news@example.com'
admin_address: 'admin@example.com'
diff --git a/config/services/providers.yml b/config/services/providers.yml
index b7b66be8..481b23a3 100644
--- a/config/services/providers.yml
+++ b/config/services/providers.yml
@@ -7,12 +7,6 @@ services:
arguments:
$config: '%app.config%'
- PhpList\Core\Domain\Common\IspRestrictionsProvider:
- autowire: true
- autoconfigure: true
- arguments:
- $confPath: '%app.phplist_isp_conf_path%'
-
PhpList\Core\Domain\Subscription\Service\Provider\CheckboxGroupValueProvider:
autowire: true
PhpList\Core\Domain\Subscription\Service\Provider\SelectOrRadioValueProvider:
@@ -30,3 +24,6 @@ services:
PhpList\Core\Domain\Subscription\Service\Provider\SubscriberAttributeChangeSetProvider:
autowire: true
+
+ PhpList\Core\Domain\Common\IspRestrictionsProvider:
+ autowire: true
diff --git a/config/services/repositories.yml b/config/services/repositories.yml
index ea1f0001..37b31c18 100644
--- a/config/services/repositories.yml
+++ b/config/services/repositories.yml
@@ -22,6 +22,11 @@ services:
arguments:
- PhpList\Core\Domain\Configuration\Model\EventLog
+ PhpList\Core\Domain\Configuration\Repository\UrlCacheRepository:
+ parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
+ arguments:
+ - PhpList\Core\Domain\Configuration\Model\UrlCache
+
PhpList\Core\Domain\Identity\Repository\AdministratorRepository:
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
@@ -145,3 +150,13 @@ services:
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
arguments:
- PhpList\Core\Domain\Messaging\Model\MessageData
+
+ PhpList\Core\Domain\Messaging\Repository\AttachmentRepository:
+ parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
+ arguments:
+ - PhpList\Core\Domain\Messaging\Model\Attachment
+
+ PhpList\Core\Domain\Messaging\Repository\MessageAttachmentRepository:
+ parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
+ arguments:
+ - PhpList\Core\Domain\Messaging\Model\MessageAttachment
diff --git a/config/services/resolvers.yml b/config/services/resolvers.yml
index 99c08356..6dfab328 100644
--- a/config/services/resolvers.yml
+++ b/config/services/resolvers.yml
@@ -13,3 +13,27 @@ services:
PhpList\Core\Bounce\Service\BounceActionResolver:
arguments:
- !tagged_iterator { tag: 'phplist.bounce_action_handler' }
+
+ PhpList\Core\Domain\Configuration\Service\Placeholder\UnsubscribeUrlValueResolver:
+ autowire: true
+ autoconfigure: true
+
+ PhpList\Core\Domain\Configuration\Service\Placeholder\ConfirmationUrlValueResolver:
+ autowire: true
+ autoconfigure: true
+
+ PhpList\Core\Domain\Configuration\Service\Placeholder\PreferencesUrlValueResolver:
+ autowire: true
+ autoconfigure: true
+
+ PhpList\Core\Domain\Configuration\Service\Placeholder\SubscribeUrlValueResolver:
+ autowire: true
+ autoconfigure: true
+
+ _instanceof:
+ PhpList\Core\Domain\Configuration\Service\Placeholder\PlaceholderValueResolverInterface:
+ tags: ['phplist.placeholder_resolver']
+ PhpList\Core\Domain\Configuration\Service\Placeholder\PatternValueResolverInterface:
+ tags: [ 'phplist.pattern_resolver' ]
+ PhpList\Core\Domain\Configuration\Service\Placeholder\SupportingPlaceholderResolverInterface:
+ tags: [ 'phplist.supporting_placeholder_resolver' ]
diff --git a/config/services/services.yml b/config/services/services.yml
index cf298621..3121e9d3 100644
--- a/config/services/services.yml
+++ b/config/services/services.yml
@@ -1,4 +1,9 @@
services:
+ _defaults:
+ autowire: true
+ autoconfigure: true
+ public: false
+
PhpList\Core\Domain\Subscription\Service\SubscriberCsvExporter:
autowire: true
autoconfigure: true
@@ -12,9 +17,6 @@ services:
PhpList\Core\Domain\Messaging\Service\EmailService:
autowire: true
autoconfigure: true
- arguments:
- $defaultFromEmail: '%app.mailer_from%'
- $bounceEmail: '%imap_bounce.email%'
PhpList\Core\Domain\Subscription\Service\SubscriberDeletionService:
autowire: true
@@ -43,6 +45,55 @@ services:
autowire: true
autoconfigure: true
+ PhpList\Core\Domain\Common\OnceCacheGuard:
+ autowire: true
+ autoconfigure: true
+
+ # Html to Text converter used by mail constructors
+ PhpList\Core\Domain\Common\Html2Text:
+ autowire: true
+ autoconfigure: true
+
+ # Rewrites relative asset URLs in fetched HTML to absolute ones
+ PhpList\Core\Domain\Common\HtmlUrlRewriter:
+ autowire: true
+ autoconfigure: true
+
+ PhpList\Core\Domain\Common\PdfGenerator:
+ autowire: true
+ autoconfigure: true
+
+ PhpList\Core\Domain\Messaging\Service\AttachmentAdder:
+ autowire: true
+ autoconfigure: true
+
+ PhpList\Core\Domain\Configuration\Service\UserPersonalizer:
+ autowire: true
+ autoconfigure: true
+
+ # External image caching/downloading helper used by TemplateImageEmbedder
+ PhpList\Core\Domain\Common\ExternalImageService:
+ autowire: true
+ autoconfigure: true
+ arguments:
+ $tempDir: '%kernel.cache_dir%'
+ # Use literal defaults if parameters are not defined in this environment
+ $externalImageMaxAge: 0
+ $externalImageMaxSize: 204800
+ $externalImageTimeout: 30
+
+ # Embed images from templates and filesystem into HTML emails
+ PhpList\Core\Domain\Messaging\Service\TemplateImageEmbedder:
+ autowire: true
+ autoconfigure: true
+ arguments:
+ $documentRoot: '%kernel.project_dir%/public'
+ # Reuse upload_images_dir for editorImagesDir if a dedicated parameter is absent
+ $editorImagesDir: '%phplist.upload_images_dir%'
+ $embedExternalImages: '%messaging.embed_external_images%'
+ $embedUploadedImages: '%messaging.embed_uploaded_images%'
+ $uploadImagesDir: '%phplist.upload_images_dir%'
+
PhpList\Core\Domain\Messaging\Service\RateLimitedCampaignMailer:
autowire: true
autoconfigure: true
@@ -120,9 +171,13 @@ services:
autoconfigure: true
public: true
- PhpList\Core\Domain\Configuration\Service\UserPersonalizer:
+ PhpList\Core\Domain\Configuration\Service\MessagePlaceholderProcessor:
autowire: true
autoconfigure: true
+ arguments:
+ $placeholderResolvers: !tagged_iterator phplist.placeholder_resolver
+ $patternResolvers: !tagged_iterator phplist.pattern_resolver
+ $supportingResolvers: !tagged_iterator phplist.supporting_placeholder_resolver
PhpList\Core\Domain\Configuration\Service\LegacyUrlBuilder:
autowire: true
@@ -139,3 +194,28 @@ services:
autoconfigure: true
arguments:
$maxMailSize: '%messaging.max_mail_size%'
+
+ # Loads and normalises message data for campaigns
+ PhpList\Core\Domain\Messaging\Service\MessageDataLoader:
+ autowire: true
+ autoconfigure: true
+ arguments:
+ $defaultMessageAge: '%app.config.default_message_age%'
+
+ # Common helpers required by precache/message building
+ PhpList\Core\Domain\Common\TextParser:
+ autowire: true
+ autoconfigure: true
+
+ PhpList\Core\Domain\Common\RemotePageFetcher:
+ autowire: true
+ autoconfigure: true
+
+ # Pre-caches base message content (HTML/Text/template) for campaigns
+ PhpList\Core\Domain\Messaging\Service\MessagePrecacheService:
+ autowire: true
+ autoconfigure: true
+ arguments:
+ $useManualTextPart: '%messaging.use_manual_text_part%'
+ $uploadImageDir: '%phplist.upload_images_dir%'
+ $publicSchema: '%phplist.public_schema%'
diff --git a/resources/translations/messages.en.xlf b/resources/translations/messages.en.xlf
index 40a24785..5259d776 100644
--- a/resources/translations/messages.en.xlf
+++ b/resources/translations/messages.en.xlf
@@ -750,6 +750,66 @@ Thank you.
phplist has started sending the campaign with subject %subject%
__phplist has started sending the campaign with subject %subject%
+
+ Unsubscribe
+ __Unsubscribe
+
+
+ This link
+ __This link
+
+
+ Confirm
+ __Confirm
+
+
+ Update preferences
+ __Update preferences
+
+
+ Sorry, you are not subscribed to any of our newsletters with this email address.
+ __Sorry, you are not subscribed to any of our newsletters with this email address.
+
+
+ This message contains attachments that can be viewed with a webbrowser
+ __This message contains attachments that can be viewed with a webbrowser
+
+
+ Insufficient memory to add attachment to campaign %campaignId% %tatalSize% - %memLimit%
+ __Insufficient memory to add attachment to campaign %campaignId% %tatalSize% - %memLimit%
+
+
+ Add us to your address book
+ __Add us to your address book
+
+
+ phpList system error
+ __phpList system error
+
+
+ Error, when trying to send campaign %campaignId% the attachment (%remoteFile%) could not be copied to the repository. Check for permissions.
+ __Error, when trying to send campaign %campaignId% the attachment (%remoteFile%) could not be copied to the repository. Check for permissions.
+
+
+ failed to open attachment (%remoteFile%) to add to campaign %campaignId%
+ __failed to open attachment (%remoteFile%) to add to campaign %campaignId%
+
+
+ Insufficient memory to add attachment to campaign %campaignId% %totalSize% - %memLimit%
+ __Insufficient memory to add attachment to campaign %campaignId% %totalSize% - %memLimit%
+
+
+ Attachment %remoteFile% does not exist
+ __Attachment %remoteFile% does not exist
+
+
+ Error, when trying to send campaign %campaignId% the attachment (%remoteFile%) could not be found in the repository.
+ __Error, when trying to send campaign %campaignId% the attachment (%remoteFile%) could not be found in the repository.
+
+
+ Location
+ __Location
+