SparkPost Mail Transport for XF 2.2

SparkPost Mail Transport for XF 2.2 2.1.4

No permission to download
Last edited:
I assume that one can always set their emails by domain rather than by individual email addresses?

The AI mentioned that I could manage this using a DomainKey, for example, sending send@forum to SparkPost while keeping post@forum with the old host. But I suspect that one has to decide on one direction?
 
I assume that one can always set their emails by domain rather than by individual email addresses?

The AI mentioned that I could manage this using a DomainKey, for example, sending send@forum to SparkPost while keeping post@forum with the old host. But I suspect that one has to decide on one direction?

I don't think I follow what you're trying to do?
 
Code:
     Exception: HashContext for algorithm "sha256" cannot be serialized src/XF/Mail/Queue.php:57

#1 src/XF/Mail/Queue.php(57): serialize(Object(Hampel\SparkPostDriver\Message))
#2 src/XF/Mail/Mailer.php(322): XF\Mail\Queue->queueForRetry(Object(Hampel\SparkPostDriver\Message), NULL)
#3 src/XF/Mail/Mail.php(459): XF\Mail\Mailer->send(Object(Hampel\SparkPostDriver\Message), Object(Hampel\SparkPostDriver\Transport\SparkPostTransport), NULL, true)
#4 src/XF/Service/User/AbstractConfirmationService.php(85): XF\Mail\Mail->send()




The error you're encountering relates to how PHP handles the serialization of objects, particularly with the sha256 hashing algorithm.

What Does the Error Mean?​

  • Error Description:
    • The error indicates that a HashContext object (used internally for hashing with the sha256 algorithm) cannot be serialized. PHP is attempting to convert the HashContext object into a storable format (a string), but this is not possible for this specific type.
  • Context of Queue.php and Mailer.php:
    • In XF\Mail\Queue.php, an attempt is being made to queue a message (specifically a Hampel\SparkPostDriver\Message object) for a retry, which requires serialization.
    • The HashContext object cannot be serialized, leading to this exception.

Why Does This Happen?​

  • Serialization Issue:
    • The HashContext is an internal PHP object created by functions like hash_init() and hash_update(). Such objects are not serializable, meaning they can't be directly converted into a string.
  • Mailing and SparkPost Driver:
    • The mail queue in your XenForo setup is trying to serialize and queue messages sent through the SparkPost driver for later retry. This fails when a non-serializable object like HashContext is involved.

Possible Solutions:​

  1. Review Mail Configuration:
    • Ensure that the SparkPost driver and related mail configuration are set up correctly, so unnecessary objects aren't being serialized.
  2. Avoid Serialization of HashContext:
    • If possible, modify the code to prevent HashContext objects from being serialized. This might involve handling the hash calculation differently before the message is queued.
  3. Check for XenForo and Add-on Updates:
    • Look for updates to XenForo or the SparkPost add-on that might address this issue. Such problems can sometimes be resolved by updates that change how messages are processed.
  4. Code Fixes:
    • If you can edit the code, ensure that the HashContext does not enter the queue. This could involve cloning the object without the HashContext part or recalculating the hash when the message is retried.

Summary:​

The error occurs because PHP is attempting to serialize a HashContext object, which is not possible. To avoid this, either the configuration or the code needs to be adjusted to ensure that such non-serializable objects do not enter the mail queue.
 
Code:
    GuzzleHttp\Exception\ClientException: Email to *****@gmx.de from noreply@*******.com failed: Client error: POST https://api.sparkpost.com/api/v1/transmissions resulted in a 401 Unauthorized response:{"errors": [ {"message": "Unauthorized."} ]
    src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113      

Stack-Trace

#0 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/guzzle/src/Middleware.php(65): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response))

#1 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/Promise.php(204): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response))

#2 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/Promise.php(153): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), NULL)

#3 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/TaskQueue.php(48): GuzzleHttp\Promise\Promise::GuzzleHttp\Promise\{closure}()

#4 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/Promise.php(248): GuzzleHttp\Promise\TaskQueue->run(true)

#5 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/Promise.php(224): GuzzleHttp\Promise\Promise->invokeWaitFn()

#6 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/Promise.php(269): GuzzleHttp\Promise\Promise->waitIfPending()

#7 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/Promise.php(226): GuzzleHttp\Promise\Promise->invokeWaitList()

#8 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()

#9 src/addons/Hampel/SparkPostMail/vendor/guzzlehttp/guzzle/src/Client.php(182): GuzzleHttp\Promise\Promise->wait()

#10 src/addons/Hampel/SparkPostMail/vendor/hampel/swiftmailer-sparkpost/src/Transport/SparkPostTransport.php(70): GuzzleHttp\Client->request('POST', 'https://api.spa...', Array)

#11 src/XF/Mail/Mailer.php(312): Hampel\SparkPostDriver\Transport\SparkPostTransport->send(Object(Hampel\SparkPostDriver\Message), NULL)

#12 src/XF/Mail/Queue.php(148): XF\Mail\Mailer->send(Object(Hampel\SparkPostDriver\Message), Object(Hampel\SparkPostDriver\Transport\SparkPostTransport), Array)

#13 src/XF/Job/MailQueue.php(12): XF\Mail\Queue->run(8)
 
I have written at 2.3 version, but it is a 2.2 version;
I have added a new api key only with the two permissions and no IP restriction like before.

Hampel\SparkPostMail:TransportTest - Sending failed: "HashContext for algorithm "sha256" cannot be serialized"; message: ""; description: ""; code: "0"
 
It took me a while to understand the system.

I have forum.com, mail.forum.com, and bounce.forum.com.
I have 2 TXT records for mail and bounce; 2 CNAME records for mail and bounce.
Everything is verified at sparks.
At cloudflare i have removed proxy from the dns values (just to have done it)
I have an API key with the necessary permissions.
I have entered the key in "use for Sparks for mail."
I have a mail-ad for sending, post, and bounce. (All three also have a mailbox at the provider, i know we dont need 2 of them now)
I checked that PHP 8.1. Now 8.2
I have ordered 50.000 mails per month for 20$ as a test.

I don't know what else to check.
 
1. It seems "SMTP" must be checked at Sparks.
2. Is your add-on done for US or Europe?
 
Last edited:
Funny, funny, I did all the steps again, this time with the US setup;

Result:

Hampel\SparkPostMail - Sending failed: "HashContext for algorithm 'sha256' cannot be serialized"; message: ""; description: ""; code: "0"
 
1. It seems "SMTP" must be checked at Sparks.
2. Is your add-on done for US or Europe?

Send via SMTP is not required - it sends via the API directly

The addon uses the US API endpoint.

I'd need to add an option to use the EU endpoint.
 
I have written at 2.3 version, but it is a 2.2 version;
I have added a new api key only with the two permissions and no IP restriction like before.

Hampel\SparkPostMail:TransportTest - Sending failed: "HashContext for algorithm "sha256" cannot be serialized"; message: ""; description: ""; code: "0"

I'm pretty sure these HashContext errors relate to DKIM errors in your DNS or sending configuration - ie it's a setup problem, not a code problem.
 
It took me a while to understand the system.

I have forum.com, mail.forum.com, and bounce.forum.com.
I have 2 TXT records for mail and bounce; 2 CNAME records for mail and bounce.
Everything is verified at sparks.
At cloudflare i have removed proxy from the dns values (just to have done it)
I have an API key with the necessary permissions.
I have entered the key in "use for Sparks for mail."
I have a mail-ad for sending, post, and bounce. (All three also have a mailbox at the provider, i know we dont need 2 of them now)
I checked that PHP 8.1. Now 8.2
I have ordered 50.000 mails per month for 20$ as a test.

I don't know what else to check.

What is the actual sending address you're using?

ie. what is the value of "defaultEmailAddress" ? Only the domain part is important - you can obfuscate the user.

You can't send from something@forum.com if you don't have a sending domain configured for forum.com

If you have a sending domain of mail.forum.com, then you need to actually send from something@mail.forum.com

The bounce domain is fine - that's only used as the return path, provided it's set as the default bounce domain
 
Phew! Thank you for responding so quickly; I've had a long, long night. It might be working now, but I'm not sure because everything seems to be so slow.

I'm not going to tell you everything I did last night. Instead, I'll ask:

Can emails be sent as post@forum.com only if forum.com is registered as the sender?Is it enough to have TXT and SPF records, since CNAME can't be entered due to A/AAAA?

Why is there an instruction to enter both TXT and CNAME records?Is it only for subdomains? But subdomains mean that you need emails like post@subdomain.forum.com, right?

Where do the emails actually end up, other than in Sparkmail?

Current status:

Forum uses SMTP to Sparkpost US (since it's paid for a month)Sender: forum.com strict, no domain for bounceForum: forum@ bounce@

bounce@ does not end up at MX bounce@forum.com

I'll now reactivate your addon and see if it works, now that the DNS seems to be okay.
 
To send emails from something@forum.com you'll need the following records:
  1. Sending domain forum.com with DKIM TXT record verified
  2. DKIM (TXT) for forum.com added to DNS
  3. SPF (TXT) for forum.com added to DNS
  4. you do NOT need the CNAME record for the forum.com sending domain
  5. bounce domain for bounce.forum.com (mark it as the default bounce domain)
  6. CNAME for bounce.forum.com => sparkpostmail.com
There should not be an MX record for bounce.forum.com.

What will happen when you send emails from something@forum.com is that SparkPost will check for a matching sending domain (step 1 above) and will then sign the message with the DKIM signature to prove who you are (step 2 above). It will also replace the return path with <some-long-string@bounce.forum.com> (step 5 above) ... which means that bounced messages return to that address (SparkPost handles the MX records at sparkpostmail.com - we don't need to do anything - step 6 above) and we see the bounced email as a message event in the admin area.

We never get to see the bounced emails - they are captured by SparkPost. We use the message events API to query them and deal with bounced emails - my addon takes care of all of that for you, no mailbox required.
 
Thank you very much.
I don't need to see the bounces in an inbox because you fetch them via api.
What is with TXT for bounce.forum.com, not mentioned above?

Doing the same with smtp and without your addon as long the EU is not ready to use?
The same as above but sending domain strict, no bounce ...

Just for understanding SMTP

XF, Mail => Sparkpost => receiver server => sorry, no mailbox

=> back to sparkpost (=sender) or
=> back to mailadress in header bounce@forum.com?

Case 1, can have the bounced mail to my inbox bounce@forum.com from Sparkpost?


Just for understanding your addon

XF, Mail => Sparkpost => receiver server => sorry, no mailbox
=> back as bounced to sparkpost (=sender)
=> back as info to your addon => set mail as bounced

Sending via SMTP achieves exactly the same thing as sending via API and works the same way as far as mail is concerned - it's just a different protocol (SMTP vs HTTP). The configuration is the same at the SparkPost end - you just need an API key with "Send via SMTP enabled".

However, you just get less flexibility when sending via SMTP because it's not as easy to set the various options such as flagging messages as transactional, click and open tracking, etc.

It can also be much faster to send via API - SMTP has a whole heap of handshakes it needs to do when sending mails - which slows things down a lot.

The DKIM TXT record for bounce domains is just poorly explained UI on their part - it's only used if you have the same domain used for both sending and bounce. For example: sending from post@mail.forum.com, you can configure SparkPost with a single domain entry which does both sending and bounces.

You can't do that with a root domain (post@forum.com) because you can't set a CNAME on the root because your A records already point to your website - hence the need for two domains in SparkPost (one for sending, one for bounce).

It's a bit confusing, but once you understand what the purpose of each is and how it relates to sending from the root domain vs a subdomain, it does generally make sense.
 
Back
Top Bottom