Stripe get customer email address - stripe-payments

I'm trying to yet up a subscription using Stripe checkout.js and then using PHP to Subscribe customers. My problem is getting their email address. Can't find anything useful in the docs.
Docs here: https://stripe.com/docs/guides/subscriptions#step-2-subscribe-customers
What I have:
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton">Purchase</button>
<script>
var handler = StripeCheckout.configure({
key: 'pk_test_keyhere',
image: '/square-image.png',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
}
});
document.getElementById('customButton').addEventListener('click', function(e) {
// Open Checkout with further options
handler.open({
name: 'test2',
description: 'Test Des',
amount: 0001,
currency:'GBP'
});
e.preventDefault();
});
</script>
<?php
// Set your API key
Stripe::setApiKey("sk_test_keyhere");
$token = $_POST['stripeToken'];
$customer = Stripe_Customer::create(array(
"card" => $token,
"plan" => "test2",
"email" => $email
)
);
?>

Adding to David's answer, you can retrieve the email address via PHP like so:
$stripeinfo =Stripe_Token::retrieve($_POST["token"]);
echo '<pre>',print_r($stripeinfo),'</pre>'; //show stripeObject info
$email = $stripeinfo->email;
Adding a small update to this answer for people who are coming across this now.
$token = $_POST['stripeToken'];
$stripeinfo = \Stripe\Token::retrieve($token);
$email = $stripeinfo->email;
$customer = \Stripe\Customer::create(array(
'email' => $email,
'source' => $token,
'description' => 'New Customer'
));
Just some small changes I had to make to get my code to work.

If you are using Checkout you will be passed a token, using that token you can obtain the email address through an API call: https://stripe.com/docs/api#retrieve_token
Not sure why email isn't listed under there but I do have an email attribute available to me. You can also see the email under the Stripe's logs.

Related

Azure App Service SNAT port exhaustion on Sendgrid connection

I am having a nodejs code trigerring sendgrid email to 1000+ users. When the number users is less (100-200)this works fine. But when there are 1000+ users it fails at a point and the rest of the mails are not triggered. When i check the app service it is shown as SNAT port exhaustion.
userList.forEach(async(Element) => {
console.log(Element.userId);
let textContentUser="";
let emailContentUser="";
textContentUser=textContent;
var userData=await db.collection('masterUserDetails').find({"userId":Element.userId}).toArray();
if(userData.length>0)
{
textContentUser=textContentUser.split("{{FirstName}}").join(userData[0]["givenName"]);
textContentUser=textContentUser.split("{{FullName}}").join(userData[0]["preferredName"]);
var leadReviewerData=await db.collection('masterUserDetails').find({"userId":userData[0]["counselorEmail"]}).toArray();
if(leadReviewerData.length==0)
{
textContentUser=textContentUser.split("{{LeadReviewerFullName}}").join(userData[0]["counselorName"]);
textContentUser=textContentUser.split("{{LeadReviewerFirstName}}").join(userData[0]["counselorName"]);
}
else
{
textContentUser=textContentUser.split("{{LeadReviewerFullName}}").join(leadReviewerData[0]["preferredName"]);
textContentUser=textContentUser.split("{{LeadReviewerFirstName}}").join(leadReviewerData[0]["givenName"]);
}
}
console.log("final Text cintent: ",textContentUser);
emailContentUser=emailContent;
emailContentUser=emailContentUser.replace("***content***",textContentUser);
//console.log("final email cintent: ",emailContentUser);
const msg = {
to: Element.userId, // Change to your recipient
bcc:"support_test#abc.com",
from: {
"email": "support#abc.com",
"name": "MY APP"
}, // Change to your verified sender
subject: emailSubject,
html: emailContentUser,
attachments: [
{
filename:"image002.gif",
content: img2,
content_id:"image002",
disposition:"inline"
},
{
filename:"image004.gif",
content: img4,
content_id:"image004",
disposition:"inline"
}],
reply_to: {
"email": "support.test#abc.com",
"name": "My APP Support"
},
send_at: sendAt
}
console.log("sending mail")
sgMail
.send(msg)
.then((response) => {
console.log("Success--------"+response[0].statusCode)
//console.log(response[0].headers)
})
.catch((error) => {
// console.log("error");
console.log("Error--------"+JSON.stringify(error))
})
});
This works in local. works when deployed in azure with lesser users also.
As others have noted, you're running out of SNAT ports to make the HTTP request to the SendGrid API.
I would recommend avoiding making an HTTP request for every email you want to send and instead use the built-in APIs to send multiple emails using one HTTP request.
To do so, add a personalizations property to your msg with an array. Add objects to the array to override the msg properties for that specific personalization, properties like subject, from, to, etc. as documented here. You can add a max of 1000 items to the personalizations array. So if you want to send more than 1000 emails, you'll need to create a separate msg for every 1000 emails, but now you only send a single HTTP request for every 1000 emails, so you shouldn't run into SNAT port errors as quickly.
Now, if you're using a single email body template but want to personalize the email, you can use Substitution Tags in your template and add a substitutions property to your personalization objects with an object holding the data you want to substitute.
Note: The total collective size of your substitutions may not exceed 10,000 bytes per personalization object.
The default substitution wrapper is "{{" and "}}" for the node.js library. Here's an example how using one msg, you can send multiple emails using personalizations and substitutions:
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const recipients = [
{
emailAddress: "recipient1#email.address",
preferredName: "Jonny",
counselorName: "Smith"
},
{
emailAddress: "recipient2#email.address",
preferredName: "Jay",
counselorName: "Smith"
}
];
const msg = {
// this will create an array of objects with `to` and `substitutions ` properties
personalizations: recipients.map(r => {
return {
to: r.emailAddress,
substitutions: {
preferredName: r.preferredName,
counselorName: r.counselorName
}
}
}),
from: 'your#sendgrid.sender',
subject: 'Ahoy!',
html: `<p>Ahoy {{preferredName}}!</p>
<p>It is a pleasure to meet you.</p>
<p>Best, {{counselorName}}</p>`
};
sgMail.send(msg).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
Pay attention to the html template containing substitution tags like {{preferredName}} and {{counselorName}}. These tag names have to match with the keys of the object in the substitutions property.
Warning: Substitution tags will not automatically HTML encode user input, so you have to HTML encode it yourself to prevent HTML injection attacks. You can learn more about HTML injection attacks here.
If you don't need to store the email body template in your code, you can use Dynamic Email Template as shown in this sample. You can create Dynamic Email Templates in the SendGrid app and use handlebar templating to add template data into your emails.
Updating the previous example with Dynamic Email Templates would look like this:
const msg = {
// this will create an array of objects with `to` and `dynamicTemplateData` properties
personalizations: recipients.map(r => {
return {
to: r.emailAddress,
dynamicTemplateData: {
preferredName: r.preferredName,
counselorName: r.counselorName
}
}
}),
from: 'your#sendgrid.sender',
templateId: 'd-[REPLACE_WITH_YOUR_TEMPLATE_ID]'
};
sgMail.send(msg).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
The subject and substitutions properties have been removed. The templateId and dynamicTemplateData have been added.
Note: Dynamic Email Templates use handlebar templating which will HTML encode user input, protecting you from HTML injection.
Last suggestion: Twilio recommends schedule your bulk emails by using the sendAt property instead of sending them right now.
Quoting from the SendGrid docs:
This technique allows for a more efficient way to distribute large
email requests and can improve overall mail delivery time performance.
This functionality:
Improves efficiency of processing and distributing large volumes of email.
Reduces email pre-processing time.
Enables you to time email arrival to increase open rates.
Is available for free to all SendGrid customers.

Integrate iDeal with Stripe Connect To Split Payments

I'm running a marketplace website using Dokan Pro where I have integrated Stripe Connect. Now I want to integrate iDeal with it but they don't have it officially so I'm following Stripe's documentation to do some custom coding but I'm not able to achieve anything so far.
Stripe provided me this documentation:
https://stripe.com/docs/connect/direct-charges#create-a-charge
There's an official plugin on Stripe For Woocommerce that also has iDeal option but the problem is that it doesn't split payment because it doesn't work with Stripe Connect. I did try to edit it's code but it gives me an error when I send the application_fee parameter. Here's the code:
public function create_source( $order ) {
$currency = $order->get_currency();
$return_url = $this->get_stripe_return_url( $order );
$post_data = array();
$post_data['amount'] = WC_Stripe_Helper::get_stripe_amount( $order->get_total(), $currency );
$post_data['currency'] = strtolower( $currency );
$post_data['type'] = 'ideal';
$post_data['application_fee_amount'] = '10';
$post_data['owner'] = $this->get_owner_details( $order );
$post_data['redirect'] = array( 'return_url' => $return_url );
if ( ! empty( $this->statement_descriptor ) ) {
$post_data['statement_descriptor'] = WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor );
}
WC_Stripe_Logger::log( 'Info: Begin creating iDeal source' );
return WC_Stripe_API::request( apply_filters( 'wc_stripe_ideal_source', $post_data, $order ), 'sources' );
}
Any help would be appreciated.
Assumption: I'm assuming for "split payments" you mean to handle when a customer does a single order/payment to your platform which includes goods/services from more than one provider. You need to allocate the payment and send some of it to more than one destination account.
A couple of items that I think are making things difficult for you:
Rather than Sources, I'd recommend looking at the updated Payment Intents guide for iDEAL. You should find this aligns much better with all the most recent documentation across Stripe's API.
If you're intending to split payments to multiple recipients, you will not be able to do so with direct charges. Instead, you should use "Separate Charges & Transfers" to allow you to send portions of the payment to more than one provider of goods/services.
On server:
// Create a PaymentIntent:
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => 10000,
'currency' => 'eur',
'payment_method_types' => ['ideal'],
'transfer_group' => 'YOUR_ORDER_ID_123',
]);
// Send $paymentIntent->client_secret to the client
On client:
//HTML
<div id="ideal-bank-element">
<!-- A Stripe Element will be inserted here. -->
</div>
//JS
// Create an instance of the idealBank Element
var idealBank = elements.create('idealBank', options);
// Add an instance of the idealBank Element into
// the `ideal-bank-element` <div>
idealBank.mount('#ideal-bank-element');
...
stripe.confirmIdealPayment(
'{{PAYMENT_INTENT_CLIENT_SECRET}}',
{
payment_method: {
ideal: idealBank,
billing_details: {
name: accountholderName.value,
},
},
return_url: 'https://your-website.com/checkout/complete',
}
);
On server, later:
// Create a Transfer to a connected account (later):
$transfer = \Stripe\Transfer::create([
'amount' => 7000,
'currency' => 'eur',
'destination' => 'acct_123',
'transfer_group' => 'YOUR_ORDER_ID_123',
]);
// Create a second Transfer to another connected account (later):
$transfer = \Stripe\Transfer::create([
'amount' => 2000,
'currency' => 'eur',
'destination' => 'acct_456',
'transfer_group' => 'YOUR_ORDER_ID_123',
]);

Stripe - Cannot charge a customer that has no active card

I have the follow block of PHP code which generates a new Stripe customer using a token, since i don't want to handle the card details on my server
$stripe_customer = \Stripe\Customer::create(array(
'source' => $token,
'description' => $displayname,
'metadata' => array('BHAA_ID'=>$bhaa_id),
'email' => $email
)
);
$stripe_customer_id=$stripe_customer->id;
I then attempt to register the card with these calls
$customer = \Stripe\Customer::retrieve($stripe_customer_id);
$card = $customer->sources->create(array("source" => $token));
The final step is to then charge the created customer like this using the customer id
// https://stripe.com/docs/api?lang=php#create_charge
$charge = \Stripe\Charge::create(array(
'amount' => $amount*100,
'currency' => 'eur',
'customer' => $stripe_customer->id,
'description' => $booking_description,
'metadata' => array("booking_id" => $booking_id, "event_name" => $booking_description),
'statement_descriptor' => "abc",
'receipt_email' => get_userdata($user_id)->user_email
));
This was working, but i recently updated to the 3.5.0 version of the stripe PHP API. I'm now getting this error
Booking could not be created:
Connection error:: "Cannot charge a customer that has no active card"
From what i can make out, it now seems that I have to register a card with the customer but I can't find any examples of this.
Any advise would be appreciated.
EDIT - Add stripe dashboard details
From the stripe dashboard, I can see that my customer is registered. This is in the response log
id: cus_7Xq5jNrrLfv73U
object: "customer"
account_balance: 0
created: 1450292050
currency: null
default_source: null
delinquent: false
description: "Web Master"
This is a screen shot of the 'Register Card' request. I can see that the 'customer id' is present in the URL, but the source parameter is not present as a Query Parameter or in the post body.

Omnipay Stripe Extra Parameters

Im trying to use the Omnipay API with Stripe, but I can't pass in extra parameters such as "Name", "Metadata", or "Zip".
// The token is grabbed from stripe JS
$this->stripe_gateway = Omnipay::create('Stripe');
$response = $this->stripe_gateway->purchase([
'amount' => $amount,
'currency' => 'usd',
'name' => $name,
'description' => $product->title,
'zip_address' => $zip,
'metadata' => [
'name' => $name,
'user_id' => $this->session->get('id')
],
'token' => $stripeToken,
])->send();
I cant get anything to work, is this not built into the API?
Omnipay uses it's own parameter names, not Stripe's. That's because Omnipay tries to abstract most of the differences between the various payment gateways.
Right now, the omnipay/stripe package doesn't support sending some of those parameters (only amount, currency, description, and now metadata). You can see the supported parameters here:
https://github.com/omnipay/stripe/blob/master/src/Message/AuthorizeRequest.php
That said, you can still easily access the underlying Stripe request to add your own custom parameters:
$request = $this->stripe_gateway->purchase([
'amount' => $amount,
'token' => $stripeToken,
'metadata' => ['foo' => 'bar'],
]);
$data = $request->getData();
$data['zip_address'] = '12345';
$data['another_custom_parameter'] = 'wow';
$response = $request->sendData($data);
Note that:
$data = $request->getData();
$response = $request->sendData($data);
is exactly the same as calling:
$response = $request->send();
Alternatively, you could create a pull request to add extra parameters to the Omnipay Stripe package. I just added the metadata parameter as an example of this:
https://github.com/omnipay/stripe/commit/99c82dc42c7c0b9ec58d8c4fb917f3dc5d1c23e2

NodeJS Sendgrid Issue in sending email to multiple recipients

I am having issue in sending mails to multiple recipients.
My script is
var SendGrid = require('sendgrid').SendGrid;
var sendgrid = new SendGrid('<<username>>', '<<password>>');
sendgrid.send({
to: 'nabababa#gmail.com',
from: 'sengupta.nabarun#gmail.com',
bcc: ["sengupta.nabarun#gmail.com","sengupta_nabarun#rediffmail.com"],
I have two questions here
Can I have an array of recipients in to list?
How can I get an array of recipients in bcc list?
Solutions related to above two queries will be indeed helpful
Thanks
Nabarun
You may use an array of recipients in both the to and bcc fields.
For example:
var SendGrid = require('sendgrid').SendGrid;
var sendgrid = new SendGrid('{{sendgrid username}}', '{{sendgrid password}}');
sendgrid.send({
to: ['one#example.com', 'two#example.com'],
from: 'nick#sendgrid.com',
bcc: ['three#example.com', 'four#example.com'],
subject: 'This is a demonstration of SendGrid sending email to mulitple recipients.',
html: '<img src="http://3.bp.blogspot.com/-P6jNF5dU_UI/TTgpp3K4vSI/AAAAAAAAD2I/V4JC33e6sPM/s1600/happy2.jpg" style="width: 100%" />'
});
If this isn't working for you and Node isn't spitting out any errors, check to see if the emails are being sent, by logging into SendGrid's website and looking at the Email Activity Log.
One thing I came across while testing your code sample is if you're sending the to and bcc to the same gmail address, gmail will combine it all into one email (so it appears it didn't work). Make sure when testing you're sending email to entirely different accounts.
If you need some email accounts to test with Guerrilla Mail is an excellent option for creating temporary test accounts.
This is the solution that I ended up with and thought it was more straightforward and could be helpful for folks.
Note the difference in the shape of the personalizations object.
Recipients can see each other:
const sgMail = require('#sendgrid/mail')
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
// Declare the content we'll use for the email
const FROM_EMAIL = 'example#example.io' // <-- Replace with your email
const subject = 'Test Email Subject'
const body = '<p>Hello HTML world!</p>'
const recipients = ['alice#example.com', 'bob#example.com'] // <-- Add your email(s) here to test
// Create the personalizations object that will be passed to our message object
let personalizations = [{
to: [],
subject
}]
// Iterate over our recipients and add them to the personalizations object
for (let index in recipients) {
personalizations[0].to[index] = { email: recipients[index] }
}
const msg = {
personalizations,
from: FROM_EMAIL,
html: body,
}
// Log to see what our message object looks like
console.log(msg)
// Send the email, if success log it, else log the error message
sgMail.send(msg)
.then(() => console.log('Mail sent successfully'))
.catch(error => console.error(error.toString()))
Personalizations Object:
{
personalizations: [{
to: [
{email: "alice#example.com"},
{email: "bob#example.com"},
],
subject: "Test Email Subject"
}]
}
Recipients can not see each other:
// Create the personalizations object that will be passed to our message object
personalizations = []
// Iterate over our recipients and add them to the personalizations object
for (let index in recipients) {
personalizations[index] = { to: recipients[index], subject}
}
Personalizations Object:
{
personalizations: [
{
to: "alice#example.com",
subject: "Test Email Subject"
},
{
to: "bob#example.com",
subject: "Test Email Subject"
}
]
}
I created a RunKit with the full solution and where you can test it out.
For Sendgrid's v3 API, I found their "kitchen sink" example helpful. Here is a relevant bit from it:
var helper = require('sendgrid').mail
mail = new helper.Mail()
email = new helper.Email("test#example.com", "Example User")
mail.setFrom(email)
mail.setSubject("Hello World from the SendGrid Node.js Library")
personalization = new helper.Personalization()
email = new helper.Email("test1#example.com", "Example User")
personalization.addTo(email)
email = new helper.Email("test2#example.com", "Example User")
personalization.addTo(email)
// ...
mail.addPersonalization(personalization)
The new sendgrid-nodejs update has scrapped previous implementation methods and therefore the accepted answer wont help you now.
So... just an update in case anyone lands to this thread with specific search result.
to: [
{
email: 'email1#email.com',
},
{
email: 'email2#email.com',
},
],
A solution for TypeScript (written in ts version 3.4.3 and sendGrid 7.1.1) where you don't want recipients to be able to see each other.
import * as sendGrid from '#sendgrid/mail'
type UserEmail = {
to: string
subject: string
}
// Add as many recipients as you want
recipients = ['email1#global.com', 'email2#gmail.com']
const personalizations: UserEmail[] = recipients.map(admin => ({
to: admin,
subject: 'Inject Subject Here',
}))
try {
await sendGrid.send({
from, // Inject
personalizations,
html, // Inject
})
} catch (err) {
console.log(err)
}
const personalizations looks like this
[{ to: 'email1#global.com',
subject: 'Inject Subject Here' },
{ to: 'email2#global.com',
subject: 'Inject Subject Here' }]

Resources