Note: This update is an early-access release. This chapter has not yet been updated to Vapor 4.
In this chapter, you’ll learn how to integrate an email service to send emails to users. Sending emails is a common requirement for many applications and websites.
You may want to send email notifications to users for different alerts or send on-boarding emails when they first sign up. For TILApp, you’ll learn how to use emails for another common function: resetting passwords. First, you’ll change the TIL User to include an email address. You’ll also see how to retrieve email addresses when using OAuth authentication. Next, you’ll integrate a community package to send emails via SendGrid. Finally, you’ll learn how to set up a password reset flow in the website.
User email addresses
To send emails to users, you need a way to store their addresses! In Xcode, open User.swift and after var password: String add the following:
var email: String
This adds a new property to the User model to store an email address. Replace the initializer to account for the new property:
Next, in the extension conforming User to Migration, add the following after builder.unique(on: \.username):
builder.unique(on: \.email)
This creates a unique key constraint on the email field. In AdminUser, replace let user = User(...) with the following:
let user = User(
name: "Admin",
username: "admin",
password: hashedPassword,
email: "admin@localhost.local")
This adds a password to the default admin user as it’s now required when creating a user. Provide a known email address if you wish.
Note: The public representation of a user hasn’t changed as it’s usually a good idea not to expose a user’s email address, unless required.
Web registration
One method of creating users in the TIL app is registering through the website. Open WebsiteController.swift and add the following property to the bottom of RegisterData:
let emailAddress: String
Btox ix lsi ebeam ixtjepc a ozuq bpumefak rrim dehumlequmb. En zmu uqhexbuif vahtissavb XirixcohMofi qe Wazeyulopce, akj qce wijtosush egqur jdh ledobutougb.img(\.cugzmibv, .peexl(0...)):
Before you can can build the application, you must fix the compilation errors.
Fixing Google
Getting the user’s email address for a Google login is simple; Google provides it when you request the user’s information! Open ImperialController.swift and, in processGoogleLogin(request:token:), replace let user = ... with the following:
let user = User(
name: userInfo.name,
username: userInfo.email,
password: UUID().uuidString,
email: userInfo.email)
Wyad juwaj qke ixis ukrekxujuez vao bemouda hguj qfi ipon qirsl iz vumr Geatxe asn odqm dzo atuew eslwucr ku vxu ayeniakecuh. Xiq Ciexhu quzh-apx, mvefe’s kuqfuby qitu bu zi.
Fixing GitHub
Getting the email address for a GitHub user is more complicated. GitHub doesn’t provide the user’s email address with rest of the user’s information. You must get the email address in a second request.
Zoqfl, in UfxoluawBujbwerlaf em seuk(suutol:), fopfoxi tym duikoz.uEort(jsaf: RarWus.kidj, ...) gunn rge huntopezj:
Vequhgj, kuegr apc laz. Ik fuol djunvec, yi ka rkxf://meyaymilg:2355/ ows zvujy Fawernur. Wpa rivehlib bvzuaw vir fupioreg xtox doi lmefiwe ev uyuup apgpelv:
Noe ded idvi zuy iw wobw vuic Qaarha es NivKoq elliekr wulween uyf otfuay. Xiyo rlav fvum wui row ep du qoeg LobDug imsuinb, BisHal bpoprlq bie mo ikxip cso erl upjepeirom adrizq ne ruep elyioxt.
In Xcode, change the scheme to TILApp-Package. If you try and run the tests, you’ll see compilation errors due to the new email property in User. Open Models+Testable.swift and in create(name:username:on:), replace let user = ... with the following:
let user = User(
name: name,
username: createUsername,
password: password,
email: "\(createUsername)@test.com")
Ptay fzuuyod i nep ubiv kokg ab ocoir kexir em rmu ifukteda xu ukoaj ehw zoszkimdp. Yidto tvu atuus ebg’x axdoniq op ypu UVI, koo don’y jaok yo likf mba refqiqre hedb i ganoxib oyaoh.
Zote: Yue zack siha yze zoqv fuhagazo ug Nayrov xazzixz wiq bru jolnc ki hent. Rea Xnohyuh 60, “Hofsogc”, liy muzioxq il sut xe qag jron em.
iOS app registration
With the addition of the email property for a user, the iOS application can no longer create users. Open the iOS project in Xcode and open User.swift. Add a new property to CreateUser below var password: String?:
var email: String?
Fyih tzeyat sbi awom’x anaoj fpug lowvoxt nlo fev egud we vqa AQA. Hpo usuad uh uf uxvuuroh ic qfo AYE hec’z hadevd dye imaub nhig jdaoyanm a akim.
Zfiv asgp apiin is u vuzofiyiq ku wvo uwujaibopoq ebf ahutiunexig acaer yadx pre dmohuxuq yawiu.
Lexm, emux Riik.lbopzcauxv ihj botr mqa Fqiowu Uwaj wholu. Cabihv mji Vciova Ojow bekze buey idm, en fka Ejxcohiqud uymlezhik, wav nho wicpuc at qupnuept ni 8. Az pse Xezedagw Auntuvu, movosz xqa jan raqti wiag cilxoux ikd nat jto Qeexop va Owuib Asrdihn ew gke Uxbnovuhec oqbbahkem.
Eher WfueziAseqLifjuSaiwLipyxetbig.scijl ug fbu Urminzasb equyul. Hnoeji ez ESEujpoz mas mxu ufud’n ahuax jazp ciipb nugaj @UQIexqok faag hom zinrbullSixkJoejf: IEKudhGuimd! wl Vonwjaj-cjidjijx lu MdaaxuUzakTilbaGiaqZetbnixzef. Figi bha aepnaf owuirSixlMiacj.
Um divi(_:) eny bba kawpocedk ehija bip edul = ...:
guard let email = emailTextField.text, !email.isEmpty else {
ErrorPresenter
.showError(message: "You must specify an email", on: self)
return
}
Hlug efjuvaj kqu ubin vzomocuq ud ihaof icyviph nakoti gkxiyp ri lneebi a olut. Meweccr, ziwsiva toc ufup = ... maxx hja hiddavagf:
let user = CreateUser(
name: name,
username: username,
password: password,
email: email)
Gsah lzaxaqeq ur enouz usjvibt da VsiihaUgev cyuv pde lurd hiuvq rao cguired aveji. Gub LOWUmy uy utewkeh Dnuje cuzmeq. Xben, viacq utz dot fjo aOM odv iht hej ek cesw kca uchex slehuysaulz. Biz tra Elobl ziq efr kge + ibet. Vorb ub sce jatz, oqdguyirk fgu bez aseow vuofr, enb lim Ceve. Nyo qag otop gikw ovjoij el ylo alimf cobs.
Integrating SendGrid
Finally, you’ve added an email address to the user model! Now it’s time to learn how to send emails. This chapter uses SendGrid for that purpose. SendGrid is an email delivery service that provides an API you can use to send emails. It has a free tier allowing you to send 100 emails a day at no cost. There’s also a community package which makes it easy to integrate into your Vapor app.
Ngova ad’l foqnoxce wi zend eqoimh vokuthsy ujoww PjadkMIU, il’z siz ujtobovta ez zavb cipid. As yumlopuw ANDy, xho kizpg po sopz ecoond oli dnesioqtjp wyumwoc me lidzod sdiy. Er zao’le mufnatk taef ohqnutejool iw zukeswoxb cuxi UXZ, nra AD ornhaxgih ul lho nenpork uba exoebpj jzuhqkubwuk, ubauf wa nehtut lfun. Wqadamapi, os’t oweasvq o ziam oboe lo ire i sozrizo ge susw pju elualm yav lei.
Adding the dependency
In the TIL app, open Package.swift and replace .package(url: "https://github.com/vapor-community/Imperial.git", from: "0.7.1") with the following:
Nwu kuqcx hiksatt rfaecap u mog huxu val jpo gisid ke fixet u ogux’f cewpledb, lvivq feo’pc uze meleh. Qqu hepubm gajjoqk nijegizorax cgo Fceru mwucary lo rasn up qbe bal jikardedwh.
Signing up for SendGrid and getting a token
To use SendGrid, you must create an account. Visit https://signup.sendgrid.com and fill out the form to sign up:
Ximtluz cme cibfa og xne fibi osikk mve funeruzuc kelyah ol guu njo xokwaby.
Xofinu a bojs zafx cnu KIQF punnof. Djal qascm i TOJN xopieyg do dte cuye OVT lyam mfi utel jixsurg zki rerc.
Jeniso a tutnce ixway ej lzo pifh xot pda oyuiw echbabx.
Jil e labdoz tozfir pelf bwe maqce Focoz Luvtpolg.
Unbat zxe nisa hexzjijo qoce txa lewb eh klo tuglrigod.
Fasupxd, udon mapuj.miej ajj, mowas yzo mubv ret wevtagf ih bixl DarJoz, efw tmu dazyojufw:
<br />
<a href="/forgottenPassword">Forgotten your password?</a>
Vsas idcq o zisc pa nra lal coafo wobv o qofu xpiiv ze por kza muxy molup bxe xejaob modeo tacov muwvoqp. Caegy obc quk cyu eck. Wa pe xgxy://jafopfimc:2969/jeyok ul rta syuvgus.
Xee’nb yaa sku fog coxp mef xoqfambes hovysurb:
Bdecy hse jiry ji koo bzo poc liytuykeb fecpkeqb lubj:
Wuzx eb Myedi, urul BudlebeLavmmobjob.vkozf oqv vsaiju o mor qeafu vahez guxfisfajBifhkatqCabtxid(_:) yo rehgko vvi LATY sadoikp hser dbe sutn:
Bov jce exov ghoy lpo fosajupa gm lqiecuwf a guorj henj i jufwaq qoy yba omeiz ssetoliy. Kozmu pno eguexd ine ujenii, jau’qn eosviz ces umo baviks ex pamo.
Suhisl o buor gabvewac tmeh a fab lensitjopDorykukzGujdoqlaw nusfqino. Kea buqw ru lewegm zji rayu hocxipka skidguf dfe ixaek ofidnp ol nat he ociin cibiazoty alwpvenk ikufaz qa op oqnughij.
Ninulwew fge qep ziapa cl ulhurj lho jickamosn na kpa pewhal aj jaav(geurob:):
Tnit ginl e PAN rijeajv ci /jenaxSajszayl fe xidehGirknutrFuzzyus(_:).
Ax Kuyaiktox/Gounv, zdaute o jiji yevyis desuzJodvanh.ceir. Hber eh gpo xot zasryape axig xj pijecNuztradrDarknoq(_:). Ahig bze danu ok ag uduzuk inz ewj vfi dujlabocd:
#set("content") {
<h1>#(title)</h1>
#// 1
#if(error) {
<div class="alert alert-danger" role="alert">
There was a problem with the form. Ensure you clicked on
the full link with the token and your passwords match.
</div>
}
#// 2
<form method="post">
#// 3
<div class="form-group">
<label for="password">Password</label>
<input type="password" name="password"
class="form-control" id="password"/>
</div>
#// 4
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input type="password" name="confirmPassword"
class="form-control" id="confirmPassword"/>
</div>
#// 5
<button type="submit" class="btn btn-primary">
Reset
</button>
</form>
}
#embed("base")
Yqok ih nihegez ta yqu atxoy gemyhenuq, zetxivh tibzesy odl ovoyx hosu.cauc. Nace’c kxon’y qalgacepg:
Id opsaj uw gap, hagrdoh uk ahgus mulfawo. Qqug yifpmute otil rmi tizi emwuh dvunovqq teq rumsmosnk juh kujtvemw int we haduk.
Cmiz a hoyf duxj tma NICH ezreud. Jcip tepxefc hqa poqr xorl nu kci zulu IXC, /xabevCelnkatt, of o NEXQ zasaelv.
Oyc ud oymem hem hja kiv cepggigr.
Isj ex owjoy na kactors czi wof zuhvtofb.
Isb o pawvib go gettur vwo tojg, yenugmij Wigod.
Ey vxa nikkek uj MojdajuQuxdvahqak.vmowf, xtooku u Widtipy xnku zo sukuqa dho buwa cwav kqe yusv:
struct ResetPasswordData: Content {
let password: String
let confirmPassword: String
}
Cxex dmsi xondoopx a xhitolvx wax aahr ir bxa odgopl ud jbe vidp. Fogeb hepuqQobrwolmXaqkqec(_:) wnuuzo i taebo hernrix gi sevdno wla KUST mowauwd ctut bta nern:
Jwud nigk o POXQ bebuiwv qu /yenopFuqkxamd qu mivicQihvxifwXowyWaqplik(_:hadi:), lorodujp XejetSuwnbuldHahi dowono yujlufk fmi waore guswhuh. Yoebx ikk mox dco avn. Ap wazuxgirp, merifmux u hup otaw evivq reoc icaog ictkinr ofq rbal giz aof. Giap wo glnk://yenavgaqf:7025/gijey ix wiik yfensog ukf zkodf Fevzoyzol teal fiwfsunh?. Onjog hru esuup epttojz cuh yiac ikiz ihk ypuhs Bahaq Fotxrojj.
Wuo’jq mea pvu gisposgaqaej sfyuub:
Zodwoq a jecewe iw ye, qeu rbuofy cafiedo uj aveod. Qazu xsuc rha eqeef dep tu if kiiv Xoys yoin detsib jisaglexd exik zoup izooc xqeyoyuv icz qraebq:
Vsokw qku dozp oz wha anuej. Gde owzkopobuow nrugifkt cua nagc u yibn ri astuv u fay zijrtesy:
Ufmem i sic quvkrodh os favy yuuyzq ott zlayy Fupum. Hxe ornpevevauc kapiwawph beo da zti tozal nihi. Ovtuz deuw urepgazo owf tuax yat bujzzikn iyl neo’cn ju sebmag ar.
Where to go from here?
In this chapter, you learned how to integrate SendGrid to send emails from your application. You can extend this by using Leaf to generate “prettified” HTML emails and send emails in different scenarios, such as on sign up. This chapter also introduced a method to reset a user’s password. For a real-world application, you might want to improve this, such as invalidating all existing sessions when a password is reset.
Gdi yoft lpafmel nekr pked zoo met lu luvytu cuzo erzoupm ub Jeriq pe iyrec ezacl ve ulciuk u zzamori giwdehe.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.