Sendgrid-php: Fatal error: Uncaught SendGrid\Mail\TypeException

Created on 30 Oct 2019  路  9Comments  路  Source: sendgrid/sendgrid-php

I tried searching and this doesn't appear to have come up anywhere. I'm surprised, surely this isn't new??

Issue Summary

As part of my testing I tried entering an invalid email address (incorrectly formatted - robin@excellentconsul i.e. no .co.uk on the end)

Running the sendmail.php page gives the error:

Fatal error: Uncaught SendGrid\Mail\TypeException: $emailAddress must be valid and of type string. in /var/sites/d/mydomain.co.uk/public_html/sendgrid/lib/mail/EmailAddress.php:76 Stack trace: #0 /var/sites/d/mydomain.co.uk/public_html/sendgrid/lib/mail/EmailAddress.php(51): SendGrid\Mail\EmailAddress->setEmailAddress('robin@excellent...') #1 /var/sites/d/mydomain.co.uk/public_html/sendgrid/lib/mail/Mail.php(199): SendGrid\Mail\EmailAddress->__construct('robin@excellent...', 'Robin Miller', Array) #2 /var/sites/d/mydomain.co.uk/public_html/sendgrid/lib/mail/Mail.php(362): SendGrid\Mail\Mail->addRecipientEmail('\SendGrid\Mail\...', 'robin@excellent...', 'Robin Miller', Array, NULL, NULL) #3 /var/sites/d/mydomain.co.uk/public_html/emailtest-sendgrid.php(43): SendGrid\Mail\Mail->addTo('robin@excellent...', 'Robin Miller', Array) #4 {main} thrown in /var/sites/d/mydomain.co.uk/public_html/sendgrid/lib/mail/EmailAddress.php on line 76

EmailAddress.php line 76 says:
throw new TypeException(

The catch exception on my sendemail.php page (same as the suggested default code) says:
} catch (Exception $e) {

I'm no php expert, far from it! But from a little googling, https://wiki.php.net/rfc/throwable-interface
seems to suggest that 'Exception' and 'TypeException' are 2 different things, hence the catch Exception on the sendmail page is not catching the TypeException thrown by EmailAddress.php

Any ideas?

(I checked in the File Repository here on GH just in case I somehow managed to get an old verison but it's there as well.)

As I say, surely this isn't a new issue??!

Technical details:

  • sendgrid-php Version:
    How do I see which version I have? The latest I assume, I only downloaded it 2 days ago
  • PHP Version: 7.3
unknown or a waiting for feedback question

All 9 comments

OK, so I've found /lib/mail/TypeException.php but we're now outside my php knowledge.
So, can someone explain why I'm getting the fatal error please?!

This is a guess, but is it because /lib/loader _doesn't_ include
require_once __DIR__ . '/mail/TypeException.php';
in it when it should??

Hello @Robin-the-Frog,

Thanks for taking the time to report this!

Could you please try the following?

<?php
require 'vendor/autoload.php';

$email = new \SendGrid\Mail\Mail(); 
$email->setFrom("[email protected]", "Elmer Thomas");
$email->setSubject("Sending with Twilio SendGrid is Fun");
try {
    $email->addTo("test@example", "Bad User");
} catch (SendGrid\Mail\TypeException $e) {
    echo 'Caught type exception: '. $e->getMessage() ."\n";
}
$email->addContent("text/plain", "and easy to do anywhere, even with PHP");
$email->addContent(
    "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
);
$sendgrid = new \SendGrid(getenv('SENDGRID_API_KEY'));
try {
    $response = $sendgrid->send($email);
    print $response->statusCode() . "\n";
    print_r($response->headers());
    print $response->body() . "\n";
} catch (Exception $e) {
    echo 'Caught exception: '. $e->getMessage() ."\n";
}

Here is my result:

Caught type exception: test@example must be valid and of type string.
400
Array
(
    [0] => HTTP/1.1 400 Bad Request
    [1] => Server: nginx
    [2] => Date: Fri, 08 Nov 2019 22:20:52 GMT
    [3] => Content-Type: application/json
    [4] => Content-Length: 237
    [5] => Connection: keep-alive
    [6] => Access-Control-Allow-Origin: https://sendgrid.api-docs.io
    [7] => Access-Control-Allow-Methods: POST
    [8] => Access-Control-Allow-Headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl
    [9] => Access-Control-Max-Age: 600
    [10] => X-No-CORS-Reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html
    [11] => 
    [12] => 
)
{"errors":[{"message":"The personalizations field is required and must have at least one personalization.","field":"personalizations","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#-Personalizations-Errors"}]}

With best regards,

Elmer

Hi Elmer

Thanks for investigating.
Ah, I see, you've added another try catch block.

This is what I get (It's almost exactly the same as yours except my response_body is not quite a full as yours):-

Caught type exception: $emailAddress must be valid and of type string.

400

Array ( [0] => HTTP/1.1 400 Bad Request [1] => Server: nginx [2] => Date: Sun, 10 Nov 2019 16:20:26 GMT [3] => Content-Type: application/json [4] => Content-Length: 110 [5] => Connection: keep-alive [6] => Access-Control-Allow-Origin: https://sendgrid.api-docs.io [7] => Access-Control-Allow-Methods: POST [8] => Access-Control-Allow-Headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl [9] => Access-Control-Max-Age: 600 [10] => X-No-CORS-Reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html [11] => [12] => )

{"errors":[{"message":"The personalization block may not be null.","field":"personalizations.0","help":null}]}

It might be worth looking at using Throwable instead of Exception when catching, that way you catch all throws, not just exceptions. You can read about it here: https://www.php.net/manual/en/class.throwable.php

This is also mentioned in the link provided in the issue description, and has been available in PHP for a few years to my knowledge.

@Robin-the-Frog You ran in 2 issues:
First, a TypeException is thrown in a place you didn't expect to have one. Due to the missing @throws TypeException PHPDoc in the EmailAddress constructor, f.e. PhpStorm don't tells about it. It seems that every method in this constructor can throw TypeException.
(I will try to contribute for PHPDoc issues in separate PR - a lot of these entries are missing in other files.)

Maybe splitting your code in preparation (validation) and execution (combine together and send) will help you in preventing issues. Otherwise your complete code (from constructing Mail to send) must be in try-catch block. (After a quick review of the published examples, no one has the try-catch TypeException structures.)

Second issue is that @thinkingserious code didn't interrupt execution after catching the error. This causes even more confusion due to the failing API result. The cause of the failure is that no To recipients were assigned onto 'empty' Personalization (created by Mail constructor without arguments), so API responded an error because it was serialized to null. This one may be fixed in master #686 (not tested).

When just sending a single message, these lines of code will work for you.
Of course, customize by your needs.
(Release version 7.3.0 - PHP 7.3.12)

use SendGrid;
use SendGrid\Mail\Mail;
use SendGrid\Mail\From;
use SendGrid\Mail\To;
use SendGrid\Mail\Subject;
use SendGrid\Mail\Content;
use SendGrid\Mail\TypeException;

//  Not having the SendGrid apiKey? Reject
$apiKey = getenv('SENDGRID_API_KEY');
if (!is_string($apiKey)) {
    echo "SendGrid API key is missing";
    exit;
}

try {
    //  Compose parameters which may be fail
    $mailFrom = new From("[email protected]", "Valid sender");
    $mailTo = new To("test@example", "Bad User");
    $mailSubject = new Subject("Sending with Twilio SendGrid is Fun");

    //  Contents
    $mailContentPlain = new Content("text/plain", "and easy to do anywhere, even with PHP");
    $mailContentHtml = new Content("text/html", "<strong>and easy to do anywhere, even with PHP</strong>");
} catch (TypeException $e) {
    //  Your parameters are failing!
    echo 'Parameter exception: ' . $e->getMessage() . "\n";
    exit;
}

try {
    //  Create the Mail and try to send it
    $mail = new Mail($mailFrom, $mailTo, $mailSubject, $mailContentPlain, $mailContentHtml);
    $client = new SendGrid($apiKey);

    //  Try to send the mail which is composed
    $response = $client->send($mail);

    //  Handle/print the response
    print $response->statusCode() . "\n";
    print_r($response->headers());
    print $response->body() . "\n";
} catch (Exception $e) {
    //  SendGrid is failing...
    echo 'SendGrid exception: ' . $e->getMessage() . "\n";
    exit;
}

After fixing the 'Bad user', the message will be sent.

Damn... this may had be prevented if pull requests like this one of last year(!) was merged into a release.

Please DON'T use unvalidated/raw $_POST values - only validated input.
This error is not related to this library. Review the variables you're using.

$email = $_POST['emailToPass'];
$name = $_POST['nameToPass'];

$email = new \SendGrid\Mail\Mail();
$email->setFrom($email, $name);

Variable $email is now an instance of SendGrid\Mail\Mail. Not the unsafe input you're thinking.

thank you @kampalex for your response. I noticed I was actually using the same variable for defining my sendgrid and for my POST value. This was causing the error. I removed my comment so it doesn't create a confusion for future readers.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mwsasser picture mwsasser  路  3Comments

KayakinKoder picture KayakinKoder  路  5Comments

bjornmann picture bjornmann  路  3Comments

moontrv picture moontrv  路  3Comments

elshafey picture elshafey  路  4Comments