Replies: 9 comments 1 reply
-
To understand a bit better, are you trying to render dynamic content from an API to the react email preview app? |
Beta Was this translation helpful? Give feedback.
-
Yeah. This morning when I woke up, I thought maybe use The idea is that the API daaa while it might be dyanmic and/or static in the DB, the emails output (source, preview, etc) would be still it's static self. I came up with this:
But useSWR never fires. |
Beta Was this translation helpful? Give feedback.
-
What's the use case to fetch db to preview in the email locally? I think you could use |
Beta Was this translation helpful? Give feedback.
-
The IssueI think the biggest issue that I have seen is that fetch, axios, etc. are sync. I keep getting a promise issue when rendering. BackgroundSo my use case at least is that I am developing all these email notification for our ServiceNow implantation. #447 was the issue for that first part. So ServiceNow, in a nut shell has their email notification system divided into two parts:
So I have now:
As a sinle file in react-email and it does render out what I want. I wrote another script inside my project that will take the output of Why Dynamic?However, as part of these emails, while I can insert a "string" ${caller_id} and ServiceNow will replace it with the value that it will do based off the record it's generated from, the KB articles that I want to reference in the email notification, like polcies, etc. the links are ever changing based off the newest version that come from the KB system of ServiceNow. While I know if I make an update to the KB artcile and the link would be different, my script above I could fire at anytime to update the development instance and then I can just push it out to production without having to go into this tiny editing window which is a pain already. So I've looked through and tried different types of component structure with no luck. So the closest I come is
ServiceNow does not render code, it only has an output. If it had the ability to do it on the fly, yes, then I would be able to do it, but at this point, ServiceNow logic it doesn't. Questions?Let me know! |
Beta Was this translation helpful? Give feedback.
-
Hi @bukinoshita! This would be really useful, I'll try to explain why from my perspective. This project does not limit what kind of objects we can pass as email component props. For instance, in my project, I have classes for User and Event that are constructed from a firestore document resulting from an API call to firestore, which cannot be easily mocked. These classes provide many methods and calculated properties that can be used in the emails, better than only passing the data as a regular data object as props. Imagine an email with a props object interface Props {
user: User;
event: Event;
}
const Email = ({user, event}: Props) => {}; In order to pass a mock, what I would actually need is to make a function that calls firestore in order to get a document for user and a document for event, that I can use to construct to objects of User and Event classes, which will be my mocks. const getMockData = async () => {
const userDoc = await firestore().collection('user').doc('whatever').get();
const eventDoc = await firestore().collection('event').doc('whatever').get();
return {
user: new User(userDoc),
event: new Event(eventDoc)
}
} But then I find problems in both ways I can call my
interface Props {
user: User;
event: Event;
}
const mockData = await getMockData(); // ERROR top-level await
const Email = ({user, event}: Props = mockData) => {};
interface Props {
user: User;
event: Event;
}
const Email = ({user, event}: Props = await getMockData()) => {}; // ERROR await cannot be used in a param initializer. A way to be able to call Hope it clarifies and makes this feature be implemented sooner! Congrats for the project! |
Beta Was this translation helpful? Give feedback.
-
This could be implemented very easily with #1144 being taken into account by using Suspense and a simple hook based on Suspense's implementation. |
Beta Was this translation helpful? Give feedback.
-
We are currently using React Email in combination with a CMS in order to assemble emails. We have built many components that can be assembled in different ways and controlled via CMS. Therefore, CMS is the source of truth for how each email looks like, since it decides for each email which components and what data it will have. For the previews, I don't want to mock the CMS, but rather fetch that data. That would be the only way to respect the CMS as the source of truth. We're also deploying the preview, so it would help create better visibility of how the emails will look like for the entire company. Is there any way currently to fetch data in the preview components? |
Beta Was this translation helpful? Give feedback.
-
Same here. We are using Contentful to compose the content and would like to use react-email to preview the email before deploying them. Please let us know if there's a workaround. |
Beta Was this translation helpful? Give feedback.
-
I needed to fetch data from our CMS for the preview of emails during development. I did a quick patch using yarn patch. Here's the patch file. diff --git a/src/actions/render-email-by-path.tsx b/src/actions/render-email-by-path.tsx
index 9043a94941279ab8bb1869ab34ae559859c72bc7..67689c0ca74a0ff06f58dec99c360d5dad96d05b 100644
--- a/src/actions/render-email-by-path.tsx
+++ b/src/actions/render-email-by-path.tsx
@@ -28,7 +28,10 @@ export const renderEmailByPath = async (
const { emailComponent: Email, sourceMapToOriginalFile } = result;
- const previewProps = Email.PreviewProps || {};
+ var previewProps;
+ if(Email.SetPreviewProps) previewProps = await Email.SetPreviewProps()
+ if(Email.PreviewProps) previewProps = Email.PreviewProps || {};
+
const EmailComponent = Email as React.FC;
try {
const markup = await renderAsync(<EmailComponent {...previewProps} />, {
diff --git a/src/utils/types/email-template.ts b/src/utils/types/email-template.ts
index f64d2d21fad04504986f338f7864cdae70549bf5..527d1c3558eb891919547566a5f3c20346a5f9ab 100644
--- a/src/utils/types/email-template.ts
+++ b/src/utils/types/email-template.ts
@@ -1,6 +1,7 @@
export interface EmailTemplate {
(props: Record<string, unknown> | Record<string, never>): React.ReactNode;
PreviewProps?: Record<string, unknown>;
+ SetPreviewProps?: () => Promise<void>;
}
export const isEmailTemplate = (val: unknown): val is EmailTemplate => { |
Beta Was this translation helpful? Give feedback.
-
So, as always, emails are static. However, some of the vars, and fields that I would want filled out are still static, but the information, like a URL, data, etc. could be dynamic from an API source, database, etc.
To better illustrate this feature, I have would have this custom component:
<KB number={"0010002"}/>
This would do a AXIOS call to:
https://MYINSTANCE.service-now.com/api/now/table/
(sans the rest the of API call)... get the output of the response. Parse it and get the data I want to be able to do the render output in the email.
And on the "Desktop" view it would render:
"KB0010002" as a link to
https://my.kbsystem.link/kb?=SYS_ID
. My "KB" componey would use the<Link>
of React Email for the final output.On the "HTML" and "Plan Text" side it would still render our the URL as needed.
This way it would allow me to hardcode records inside the email render/template, but since the content is dynamic based off the version of the KB article in my example, it has to be maintained.
Ideas on how to do this? I also got some code working, however the biggest issue is that this system is designed to only work with static content and render it. This has to "pre-render" and then also "pre-output the text" before the render overall function of React Email works.
Thanks for your time.
Beta Was this translation helpful? Give feedback.
All reactions