Skip to content

Send a Single Email to a Single Recipient #331 #350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from

Conversation

M3LiNdRu
Copy link

This pull request doesn´t solve the issue #331. But it´s an inflexion point to start following the same arquitecture and conventions. Due to the refactoring I'm applying to the source code I prefered split the issue in small Pull Request.

In this PR I included:

  • Added new project for Integration Test using AAA pattern
  • Started refactor in SendGridAPIClient to follow SOLID principles
  • Created Mail Service to implement operations related to Mail

@M3LiNdRu
Copy link
Author

@thinkingserious I would like to discuss a couple of architecture concepts.

  • Following the single responsibility principle. I think Client class should be responsible for handling all HTTP stuff and API Services (Mail Service) shouldn't deal with any HTTP concept like Request or Response. EmailService only would send his Custom Request object to Client and then Client would has a internal serializer to serialize/deserialize Custom Request/Response objects.
  • Also, In my opinion, the mail helper has too much responsabilities. We should be refactored.

If you are agree with the above points, I don't have any problem to create issues for covering that.

Many Thanks

@thinkingserious
Copy link
Contributor

Hello @M3LiNdRu,

I agree with your comments on the responsibility of the Client class.

What responsibilities do you think the mail helper should cover?

@M3LiNdRu
Copy link
Author

In my opinion, regarding the api v3 reference, the mail helper it would be responsible of the mail request body parameters. I think the mail helper should be refactored as an object, not as a helper. It contains all mail info.

@thinkingserious What do you think?

…ed methods. Also, created a new method in client to send post data. Refactored classes names for convention
@thinkingserious thinkingserious added type: community enhancement feature request not on Twilio's roadmap status: cla signed status: work in progress Twilio or the community is in the process of implementing labels Oct 18, 2016
@M3LiNdRu M3LiNdRu changed the title Send a Single Email to a Single Recipient #331 Send a Single Email to a Single Recipient 1/2 #331 Oct 18, 2016
@M3LiNdRu
Copy link
Author

M3LiNdRu commented Oct 18, 2016

That PR fix the issue #331. Changes applied:

  1. Refactored Client.cs, it's splitted in two classes (SendGridAPI, SendGridHTTPClient). SendGridAPI contains the API and SendGridHttpClient all HTTP stuff. A new method has been created for posting data (PostAsync) to send grid api.
  2. Refactor Mail Helper. It´s splitted in two classes as well (Models.Mail, MailExtensions) Models.Mail contains the real object described in the SendGrid API Reference. MailExtensions contains all methods related to the Models.Mail
  3. Changed some names and following a convention. Right now, extend the code with more funcionalities is really handy and it doesn't require too much overwork. Just creating the interface/service, isolate the object to Models folder and registering the service in SendGridAPI class.

@M3LiNdRu M3LiNdRu changed the title Send a Single Email to a Single Recipient 1/2 #331 Send a Single Email to a Single Recipient #331 Oct 18, 2016

mail.TemplateId = "13b8f94f-bcae-4ec6-b752-70d6cb59f932";
mail.Personalization[0].AddSubstitution("-name-", "Example User");
mail.Personalization[0].AddSubstitution("-city-", "Denver");

dynamic response = await sg.client.mail.send.post(requestBody: mail.Get());
dynamic response = await sg.client.mail.send.post(requestBody: mail.Serialize());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed this dynamic functionality, please the code I just merged.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thinkingserious I'd say I'm not able to get this change until you accept your pull request and you merge it to the branch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, that is coming soon. I apologize for the delay. I had a couple of days of PTO and I'm currently trying to catch up. Please stay tuned ...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No hassle, there is no rush ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience!

@@ -35,13 +35,13 @@ private static void Main()
String subject = "I'm replacing the subject tag";
Email to = new Email("[email protected]");
Content content = new Content("text/html", "I'm replacing the <strong>body tag</strong>");
Mail mail = new Mail(from, subject, to, content);
SendGrid.Models.Mail mail = new SendGrid.Models.Mail(from, subject, to, content);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking we move this code behind the scenes.

I think something like this would replace this example:

String apiKey = Environment.GetEnvironmentVariable("SENDGRID_APIKEY", EnvironmentVariableTarget.User);
email = new Email(SendGrid.SendGridAPIClient(apiKey));
// The internal Email object would be renamed to Contact and the object would be instantiated behind the scenes, same with all the other getters and setters.
email.SetFrom("[email protected]");
email.AddSubject("I'm replacing the subject tag");
email.AddContent("text/html", "I'm replacing the <strong>body tag</strong>");
email.SetTemplateID("13b8f94f-bcae-4ec6-b752-70d6cb59f932");
email.AddSubstitution("-name-", "Example User");
email.AddSubstitution("-city-", "Denver");
if(email.Verify() == True){
  response = email.Send();
}
Console.WriteLine(response);
Console.ReadLine();

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree to inject the Api client as a dependency, but I think it should be injected in the EmailService not in the Email object. In my opinion, Email object should be just a DTO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

@thinkingserious
Copy link
Contributor

Please see my comments in the review, and following are my thoughts on your previous comment:

Refactored Client.cs, it's splitted in two classes (SendGridAPI, SendGridHTTPClient). SendGridAPI contains the API and SendGridHttpClient all HTTP stuff. A new method has been created for posting data (PostAsync) to send grid api.

Please see my comments along with the branch I just merged into v9beta to checkout the direction I'm thinking.

Refactor Mail Helper. It´s splitted in two classes as well (Models.Mail, MailExtensions) Models.Mail contains the real object described in the SendGrid API Reference. MailExtensions contains all methods related to the Models.Mail

I like the direction you are going. I'll dig in deeper when I finish my current tasks.

Changed some names and following a convention. Right now, extend the code with more funcionalities is really handy and it doesn't require too much overwork. Just creating the interface/service, isolate the object to Models folder and registering the service in SendGridAPI class.

Thanks for all of your help thus far. I'll be able to collaborate with you closer once I finish up my current tasks. That said, please do continue the conversation.

@thinkingserious
Copy link
Contributor

Here is my working pull request/branch: #356

@thinkingserious thinkingserious mentioned this pull request Nov 15, 2016
@jduncanator
Copy link

jduncanator commented Nov 16, 2016

Looking at this very briefly, it doesn't look like it will work very well (if at all) in multi-threaded applications. Why do you assign the mail request to the client and then call SendAsync? Why not pass the Mail model into the SendAsync method and send it from there. At least the current implementation can share a Sendgrid Client across threads. With the code in it's current state, I have to implement locking on the MailRequest member so as to make sure I do not overwrite a MailRequest from one thread whilst another thread is currently sending the email.

I personally think this is a step in the wrong direction.



//Act
_client.Mail.MailRequest = mail;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will this work in multi-threaded applications? If one thread writes to this variable whilst another thread is sending an email, you have a recipe for disaster. In it's current state it would be up to the consumer to implement locking on this variable. This should be handled internally and the library should be completely thread-safe.

@chadwackerman
Copy link

I'm sorry if any of this comes of as inappropriate but I cannot believe the amount of effort that has been expended in this thread and the end result as @jduncanator points out is junior engineering bugs.

Can you please just hire a single experienced C# dev to write this API for you? This thing is totally off in the weeds. It's taken a month for someone sane to step in and say "uh, this isn't how anyone else does it guys." Good lord.

@thinkingserious
Copy link
Contributor

@chadwackerman @jduncanator,

I'll be coming back to this thread shortly, I need to finish this first: #356

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: work in progress Twilio or the community is in the process of implementing type: community enhancement feature request not on Twilio's roadmap
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants